接上一篇JMS基础篇,现在我们将ActiveMQ与SrpingBoot集成一下,如果读者还没有了解JMS是什么的话,请先去看基础篇呗。SpringBoot提供了很便捷方法供去调用JMS。在实际项目中,通过生产者和消费者会是两个独立的应用工程, 也正是如此通过消息队列实现了解耦和广播,考虑到仅仅案例使用,本案例将两者放置在一个工程应用。
一、环境搭建
基础环境:SpringBoot+Maven+ActiveMQ,截一张项目目录图
搭建SpringBoot、Maven、ActiceMQ(在基础篇有详细说明)的过程,我就不在这里诉述了,这里主要讲集成吧
①.创建好基于SpringBoot的工程之后,在pom.xml中引入ActiveMQ包:
<!-- jms实现供应厂商 ActionMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
②.在SpringBoot的工程的配置文件[application.properties]中添加(也可以零配置,在配置类里进行配置):
#jms--ActiveMQ
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
spring.activemq.pool.enabled=false
③.添加关于ActionMQ的相关spring支持的bean,这里给出相关的启动加载的配置spring容器信息,关于ActionMQ的一些配置信息,在基础篇有提到,这里就不详述了。
package com.cheng.sbjm.configure;
import javax.jms.Queue;
import javax.jms.Topic;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.cheng.sbjm.security.LoginStatusInterceptor;
/**
* file:CustomWebMvcConfigurerAdapter.java
* @author ouyang
* 增加MVC的拦截器
*/
@Configuration //注解为此class为一个配置类
@EnableJms
public class CustomWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter{
@Override
public void addInterceptors (InterceptorRegistry registry){
registry.addInterceptor(new LoginStatusInterceptor()).addPathPatterns("/**");
}
/**
* 浏览器跨域请求处理,允许所有域名下发起的请求
* @return
*/
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
@Bean
public JmsTemplate jmsTemplate(ActiveMQConnectionFactory activeMQConnectionFactory,Queue queue){
JmsTemplate jmsTemplate=new JmsTemplate();
jmsTemplate.setDeliveryMode(2);//进行持久化配置 1表示非持久化,2表示持久化
activeMQConnectionFactory.setTrustAllPackages(true);//使用实体直接入队时配置,字符串入队列,不需要,为了演示将整个实体件入队传输。
jmsTemplate.setConnectionFactory(activeMQConnectionFactory);
//jmsTemplate.setDefaultDestination(queue); //此处可不设置默认,在发送消息时也可设置队列
jmsTemplate.setSessionAcknowledgeMode(1);//客户端签收模式
return jmsTemplate;
}
}
至此,关于springBoot与ActiveMQ的集成配置已经完成(太TN简单了!),接下来,我们来写demo来演示:
1.启动ActiveMQ的容器(具体步骤移步到基础篇哦)
2.编写消息生产者(包括点对点和话题)
package com.cheng.sbjm.service.Imp;
import javax.jms.*;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.cheng.sbjm.service.JmsProducerService;
/**
* 消息生产者
*/
@Service
public class JmsProducerServiceImpl implements JmsProducerService {
@Autowired // 也可以注入JmsTemplate,JmsMessagingTemplate对JmsTemplate进行了封装
private JmsMessagingTemplate jmsTemplate;
@Autowired
private JmsTemplate jmsTemplate;
/**
* 1生产者发送消息(发送信息到队列)
* 根据实例化Destination目的地参数的类型的对象决定是点对点队列的形式,还是广播的形式
*
*/
@Scheduled(fixedRate = 5000)
@Override
public void queueSend() {
//定义一个目的地(队列类型)
Destination queue = new ActiveMQQueue("mytest.queue");
jmsTemplate.convertAndSend(queue, "myname is Oyzc");
}
/**
* 2生产者发送消息(发送信息到话题)
*
*/
@Scheduled(fixedRate = 5000)
@Override
public void topicSend() {
//定义一个目的地(队列类型)
Destination topic = new ActiveMQTopic("mytest.topic");
jmsTemplate.convertAndSend(topic, "myname is Oyzc");
}
/**
* 3生产者发送出去消息之后,可以马上监听指定消费者的反馈信息
* @param text
*/
@Override
@JmsListener(destination="out.queue")
public void consumerMessage(String text) {
System.out.println("从out.queue队列收到的回复报文为:"+text);
}
/**
* 另外一种队列发送方式(直接传输实体)
* @param
*/
@Scheduled(fixedRate = 5000)
@Override
public void queueSend2() {
final UserRequest user=new UserRequest();
user.setUserName("ouyzc");
user.setPhone("123456789");
jmsTemplate.send("queue.lytest",new MessageCreator(){
@Override
public Message createMessage(Session session) throws JMSException {
System.out.println("发送队列!!");
return session.createObjectMessage(user);
}
});
}
/**
* 另外一种队列发送方式(传输JSON字符串)
* @param
*/
@Scheduled(fixedRate = 5000)
public void sendQueueJson(){
UserRequest user=new UserRequest();
user.setUserName("ouyzc");
user.setPhone("123456789");
String requestJson= JSON.toJSONString(user);
Destination queue = new ActiveMQQueue("json.queue");
jmsMessageingTemplate.convertAndSend(queue,requestJson);
}
}
消息生产者已经编写完成,发现点对点和话题的代码不同之处只是实例化对象不同,涉及的几个工具类。
@Scheduled(fixedRate = 5000):为了测试,定时执行5S
JmsMessagingTemplate:封装了对JMS的具体操作
Destination queue = new ActiveMQQueue("mytest.queue"); 定义队列,参数为队列名称
Destination topic = new ActiveMQTopic("mytest.topic"); 定义话题,参数为话题名称
JmsMessagingTemplate.convertAndSend(topic, "myname is Oyzc"):转化并发送队列/话题信息(第一个参数为目的地,就是上面定义的队列/话题,第二个参数是发送的内容,可以是字符串也可以是实体,不过我一般是把实体转化成JSON字符串来传输)。
这里顺便给一个JSON字符操作(阿里的)工具类:
<!-- json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.3</version>
</dependency>
//bean转化成json字符串
String requestJson= JSON.toJSONString(user);
3.编写消息消费者(包括点对点和话题)
package com.cheng.sbjm.service.Imp;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Service;
import com.cheng.sbjm.service.JmsConsumerService;
import javax.jms.*;
/**
* 消息消费者
*/
@Service
public class JmsConsumerServiceImpl implements JmsConsumerService{
// 使用JmsListener配置消费者监听的队列,其中text是接收到的消息
/**
* 消费者接收信息1(接收队列为mytest.queue的信息,并马上回复信息到out.queue队列中)
*/
@Override
// 使用JmsListener配置消费者监听的队列,其中text是接收到的消息
@JmsListener(destination = "mytest.queue")
@SendTo("out.queue")
public String receiveQueue1(String text) {
System.out.println("消费者1收到目的地为mytest.queue发来的信息"+text);
return "mytest.queue接收到你的信息了";
}
/**
* 消费者接收信息2(先订阅mytest.topic话题,后接收话题为mytest.topic的信息)
*/
@Override
@JmsListener(destination = "mytest.topic")
public void receiveTopic2(String text) {
System.out.println("消费者2收到话题为mytest.topic发来的信息"+text);
}
/**
* 消费者接收信息3(先订阅mytest.topic话题,后接收话题为mytest.topic的信息)
*/
@Override
@JmsListener(destination = "mytest.topic")
public void receiveTopic3(String text) {
System.out.println("消费者3收到话题为mytest.topic发来的信息"+text);
}
@Override
@JmsListener(destination = "queue.lytest")
public void receiveQueue2(Message message) {
if(message instanceof ObjectMessage){
ObjectMessage objectMessage=(ObjectMessage)message;
try{
UserRequest request=(UserRequest) objectMessage.getObject();
System.out.println("接收队列!!");
System.out.println(request.getUserName());
System.out.println(request.getPhone());
}catch (Exception e){
System.out.println("接收队列失败!!"+e.getMessage());
}
}
}
@JmsListener(destination = "json.queue")
public void receiveQueueJson(String requestJson){
System.out.println("接收队列:"+requestJson);
UserRequest request= JSON.parseObject(requestJson,UserRequest.class);
System.out.println(request.getUserName());
System.out.println(request.getPhone());
}
}
//json字符串转化成bean
UserRequest request= JSON.parseObject(requestJson,UserRequest.class);
消息消费者已经编写完成,涉及的几个注解。
@JmsListener(destination = "mytest.queue") :开启异步监听,监听名称为“mytest.queue”的队列/话题
@SendTo("out.queue") :返回消息给名称为“out.queue”的队列
这里为了方便测试,消息消费2和3都是接收同一个话题的消息
4.测试
利用springBoot内置的Tomcat启动工程,查看控制台发现
队列是成功发送和反馈信息了,但是话题怎么没发送呢?不急,ActiveMQ默认只打开point to point方式。
到配置文件[application.properties]中添加:
spring.jms.pub-sub-domain=true
再启动,查看控制台发现
话题也成功发送和接收了,但是队列的信息却没有,原来目前ActiveMQ只支持一种类型。
看一下ActiveMQ提供的监控
想2种同时使用的话,楼主还有待验证.......
好了,SpringBoot和ActiveMQ的集成入门篇就到这里,各位可以根据各自的业务需求,进行修改和连接前端和数据库,这只是最简单的demo,后面如果还有涉及其他真正的使用,我还会上一些真正的实例。如有错漏,请各位大神指点!