一、安装 activemq
1、去linux官网下载
wget ****
2、解压
tar -zxvf apache-activemq-5.14.0-bin.tar.gz
3、启动
./activemq start
关闭:
./activemq stop
4、开启防火墙端口
(1)如果使用了云服务器需要先开启8161(web管理页面端口)、61616(activemq服务监控端口) 两个端口
(2)打开linux防火墙端口
/sbin/iptables -I INPUT -p tcp --dport 8161 -j ACCEPT&&/etc/init.d/iptables save&&service iptables restart&&/etc/init.d/iptables status
/sbin/iptables -I INPUT -p tcp --dport 61616 -j ACCEPT&&/etc/init.d/iptables save&&service iptables restart&&/etc/init.d/iptables status
5、打开web管理页面
http://IP:8161/admin
默认用户名密码 admin/admin
二、Spring Cloud Stream Binder实现
(一)JMS 实现 ActiveMQ(原生API)
1、增加依赖
<!-- 整合 activemq:
间接依赖:
spring jms
jms api
activemq
spring boot jms
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
2、启动 ActiveMQ Broker
./activemq start
3、原生API:生产、消费消息
请注意在启动 ActiveMQ 之后控制台输出:
INFO | Listening for connections at: tcp://administrator:61616?
maximumConnections=1000&wireFormat.maxFrameSize=104857600
其中 tcp://administrator:61616
就是 brokerURL
,请注意将主机名转换成IP:tcp://192.168.10.130:61616
(1)原生API:生产消息
/**
* 生产消息
*/
private static void sendMessage() throws JMSException {
//1、创建 ActiveMQ 连接,设置 brokerURL
ConnectionFactory connectionFactory =
new ActiveMQConnectionFactory("tcp://192.168.10.130:61616");
//2、创建 JMS 连接
Connection connection = connectionFactory.createConnection();
//3、创建会话 Session(参数一 transacted:是否是事务 参数二:自动确认)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
/**
* 4、创建消息目的:
* 第一种 Queue:点对点消息
* 第二种 Topic:广播式消息
*/
Destination destination = session.createQueue("test");
//5、创建消息生产者
MessageProducer messageProducer = session.createProducer(destination);
//6、创建消息 - 文本消息
ActiveMQTextMessage message = new ActiveMQTextMessage();
message.setText("how are you?");
//7、发送文本消息
messageProducer.send(message);
//8、关闭消息发送者、Session、Connection
messageProducer.close();
session.close();
connection.close();
}
(2)原生API:消费消息
/**
* 消费消息
*/
private static void consumeMessage() throws JMSException {
//1、创建 ActiveMQ 连接,设置 brokerURL
ConnectionFactory connectionFactory =
new ActiveMQConnectionFactory("tcp://192.168.10.130:61616");
//2、创建 JMS 连接
Connection connection = connectionFactory.createConnection();
//3、启动连接(这里需要手动启动)
connection.start();
//4、创建会话 Session(参数一 transacted:是否是事务 参数二:自动确认)
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
/**
* 5、创建消息目的:
* 第一种 Queue:点对点消息
* 第二种 Topic:广播式消息
*/
Destination destination = session.createQueue("test");
//6、创建消费者
MessageConsumer consumer = session.createConsumer(destination);
//7、获取消息
Message message = consumer.receive(100);
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("----------------------------------");
System.out.println("消费消息:" + textMessage.getText());
}
//8、关闭消息发送者、Session、Connection
consumer.close();
session.close();
connection.close();
}
(二)Spring Boot + ActiveMQ
1、改造消息发送者:user-service-client 应用
(1)增加依赖
<!-- 整合 activemq:
间接依赖:
spring jms
jms api
activemq
spring boot jms
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
(2)配置 ActiveMQ 属性
#配置 ActiveMQ 属性
spring.activemq.broker-url=tcp://192.168.10.130:61616
(3)配置 JMS 属性(消息目的地)
#配置 JMS 属性(消息目的地)
spring.jms.template.default-destination=custom-destination
(4)实现 User 对象 消息发送
@Autowired
private JmsTemplate jmsTemplate;
@PostMapping("/user/save/message/activemq")
public boolean saveUserByActiveMQ(@RequestBody User user) throws IOException {
//发送消息到 ActiveMQ
jmsTemplate.convertAndSend(user);
return true;
}
2、改造消息 消费者:user-service-provider 应用
(1)增加依赖
<!-- 整合 activemq:
间接依赖:
spring jms
jms api
activemq
spring boot jms
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
(2)配置 ActiveMQ 和 JMS 属性
#配置 ActiveMQ 属性
spring.activemq.broker-url=tcp://192.168.10.130:61616
#配置 JMS 属性(消息目的地)
spring.jms.template.default-destination=custom-destination
(3)实现 消息监听(消息消费)
@Autowired
private JmsTemplate jmsTemplate;
/**
* 获取消息队列中(default-destination=custom-destination)的对象
*/
@GetMapping("/user/poll")
public Object pollUser(){
return jmsTemplate.receiveAndConvert();
}
一旦消息被消费了,则该条消息将会被 ActiveMQ 服务器删除!
(三)ActiveMQ Spring Cloud Stream Binder 实现
创建 stream-binder-activemq 工程
1、添加依赖
<!--
Spring Boot 自动装配依赖
假如你的Project A的某个依赖D添加了<optional>true</optional>,
当别人通过pom依赖Project A的时候,D不会被传递依赖进来-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<!-- 添加 activemq 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!-- Spring Cloud Stream 核心库 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
2、实现 Binder 接口 - 实现消息发送/消费
/**
* ActiveMQ MessageChannel Binder
* @author 咸鱼
* @date 2018/11/28 17:48
*/
public class ActiveMQMessageChannelBinder implements Binder<MessageChannel,
ConsumerProperties, ProducerProperties>{
@Autowired
private JmsTemplate jmsTemplate;
/**
* 接收 ActiveMQ 消息
* @param name
* @param group
* @param inboundBindTarget
* @param consumerProperties
* @return
*/
@Override
public Binding<MessageChannel> bindConsumer(String name, String group, MessageChannel inboundBindTarget, ConsumerProperties consumerProperties) {
//todo:实现消息消费
ConnectionFactory connectionFactory = jmsTemplate.getConnectionFactory();
try {
// 创造 JMS 链接
Connection connection = connectionFactory.createConnection();
// 启动连接
connection.start();
// 创建会话 Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 创建消息目的
Destination destination = session.createQueue(name);
// 创建消息消费者
MessageConsumer messageConsumer = session.createConsumer(destination);
messageConsumer.setMessageListener(message -> {
// message 来自于 ActiveMQ
if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
try {
Object object = objectMessage.getObject();
inputChannel.send(new GenericMessage<Object>(object));
} catch (JMSException e) {
e.printStackTrace();
}
}
});
} catch (JMSException e) {
e.printStackTrace();
}
return () -> {
};
}
/**
* 负责发送消息到 ActiveMQ
* @param name 配置文件中配置的 destination 名称
* @param outboundBindTarget 消息管道
* @param producerProperties
* @return
*/
@Override
public Binding<MessageChannel> bindProducer(String name, MessageChannel outboundBindTarget, ProducerProperties producerProperties) {
// MessageChannel 必须是 SubscribableChannel 类型
Assert.isInstanceOf(SubscribableChannel.class, outboundBindTarget,
"Binding is supported only for SubscribableChannel instances");
//强转为 SubscribableChannel类型
SubscribableChannel subscribableChannel = (SubscribableChannel)outboundBindTarget;
subscribableChannel.subscribe(message -> {
/*
* 接收内部管道消息,来自于 MessageChannel#send(message),实际并没有发送消息,
* 而是此消息将要发送到 ActiveMQ Broker。
* 案例:
* 我们在调用 UserServiceClientController#saveUserByActiveMQStreamBinder() 方法时,
* 会通过 messageChannel.send(message) 向 ActiveMQ 发送消息,而这里先拦截到该消息,再由
* 这里转发至 ActiveMQ
*/
Object messageBody = message.getPayload();
jmsTemplate.convertAndSend(name, messageBody);
});
return () -> System.out.println("Unbind");
}
}
3、实现 Spring Cloud Stream Binder 自动装配
/**
* ActiveMQ Stream Binder 自动装配
* @author 咸鱼
* @date 2018/11/28 18:08
*/
@Configuration
@ConditionalOnMissingBean(Binder.class)
public class ActiveMQStreamBinderAutoConfiguration {
/**
* 暴露自定义的 ActiveMQMessageChannelBinder Bean
*/
@Bean
public ActiveMQMessageChannelBinder activeMQMessageChannelBinder() {
return new ActiveMQMessageChannelBinder();
}
}
4、配置 META-INF/spring.binders
activemq:\
org.pc.activemq.ActiveMQStreamBinderAutoConfiguration
5、整合消息生产者 user-service-client 应用
(1)引入先前创建的 stream-binder-activemq 工程依赖
<!--
引入 stream-binder-activemq 项目依赖
${project.version}:该项目当前版本
-->
<dependency>
<groupId>org.pc</groupId>
<artifactId>stream-binder-activemq</artifactId>
<version>${project.version}</version>
</dependency>
(2)改造 UserMessage
/**
* 用户消息 输出
* @author 咸鱼
* @date 2018/11/24 19:14
*/
public interface UserMessage {
String OUTPUT = "output";
@Output(OUTPUT)
MessageChannel output();
@Output("activemq-output")
MessageChannel activeMQOut();
}
(3)配置 stream-binder-activemq 属性
# 消息管道 activemq-out 配置
#当项目中存在多个消息中间件:activemq、kafka,必须指定要绑定哪一个中间件
spring.cloud.stream.bindings.activemq-output.binder=activemq
spring.cloud.stream.bindings.activemq-output.destination=custom-destination
6、整合消息消费者 user-service-provider 应用
(1)引入先前创建的 stream-binder-activemq 工程依赖
<!--
引入 stream-binder-activemq 项目依赖
${project.version}:该项目当前版本
-->
<dependency>
<groupId>org.pc</groupId>
<artifactId>stream-binder-activemq</artifactId>
<version>${project.version}</version>
</dependency>
(2)改造 UserMessage
/**
* {@link User} 消息 Stream 接口定义(PS:用于管道通信)
* @author 咸鱼
* @date 2018/11/24 15:56
*/
public interface UserMessage {
String INPUT = "input";
@Input(INPUT)
SubscribableChannel input();
@Input("activemq-in")
SubscribableChannel activeMQIn();
}
(3)配置 stream-binder-activemq 属性
# 消息管道 activemq-in 配置
#当项目中存在多个消息中间件:activemq、kafka,必须指定要绑定哪一个中间件
spring.cloud.stream.bindings.activemq-in.binder=activemq
spring.cloud.stream.bindings.activemq-in.destination=custom-destination
(4)实现 User 消息监听
@StreamListener("activemq-in")
public void onUserMessage(User user) throws IOException {
System.out.println("Subscribe by @StreamListener");
userService.saveUser(user);
}
// 监听 ActiveMQ Stream
userMessage.activeMQIn().subscribe(message -> {
if (message instanceof GenericMessage) {
GenericMessage genericMessage = (GenericMessage) message;
User user = (User) genericMessage.getPayload();
userService.saveUser(user);
}
});