spring boot集成ActiveMQ

从官方demo开始

spring-cloud其他文章:
我们有必要花时间了解spring boot吗?
spring boot自动化配置原理
spring-cloud中eureka进行服务治理

spring boot提供了对JMS系统的支持,当前,只默认提供了ActiveMQ和ActiveMQ Artemis的自动配置支持。

我们一起看下spring boot如何集成ActiveMQ。首先从模仿官方的demo开始。

新建一个spring boot工程

新建方法参见我们有必要花时间了解spring boot吗?的最后一节,如何给使用工具创建spring boot项目。

这里写图片描述

选择Lombok、JMS、Web三个starter组件,点击完成。Lombok用来给模型自动添加setter、getter、constructor方法。

这里写图片描述

工具帮我们自动创建好了工程结构,添加进来了刚才选中的starter依赖。对于spring boot工程的结构,可以到官方网站了解一下,了解了之后才能明白工具到底做了什么,这样,没有工具也能创建项目,才不会编程工具的奴隶。

修改ActiveMQ配置

在application.properties中添加如下配置(spring boot的配置项默认都在这个文件里,也可以自己添加新的文件,实现不同配置的分开存储):

spring.activemq.in-memory=true
spring.activemq.pool.enabled=false

备注:实际上这两个是默认值,不配置情况下即是如此。如果你是使用spring tool suit工具或者集成到了eclipse,那么当你在application.properties里输入spring.activemq.in-memory的时候,就会提示给你默认值是什么:

这里写图片描述

添加Producer类

@RestController
public class Producer {
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Autowired
    private Queue queue;

    @RequestMapping("/sendMsg")
    public void send(String msg) {
        this.jmsMessagingTemplate.convertAndSend(this.queue, msg);
    }
}

这里做一个小的修改,使用熟悉的rest服务方式来触发发送消息的方法。

@RestController相当于指定类内部的@RequestMapping返回值都是json,就不需要添加@ResponseBody注解了。

这里的jmsMessagingTemplate和queue都是用@Autowired注解自动注入的。注意这里的jmsMessagingTemplate,在整个工程里都没有配置实例化的地方。

其实,jmsMessagingTemplate的实例化是spring boot的autoconfigure自动注入的。

实现可以参见JmsAutoConfiguration.java的代码。大概意思就是当我们引入了jms相关的包,比如activemq的包,又定义了ConnectionFactory的实例,那么他就会自动生成一个JmsTemplate实例。

ConnectionFactory在哪里自动创建的呢?看这个ActiveMQConnectionFactoryConfiguration.java。大概意思是,如果没有ConnectionFactory实例,就自动创建一个实例。

所以说,只要引入了spring-boot-starter-activemq那么就会给我们自动创建一个JmsTemplate,相关的连接配置从application.properties,如果里面没有配置的话就会使用ActiveMQProperties.java的默认值。

添加Consumer类

@Component
public class Consumer {

    @JmsListener(destination = "sample.queue")
    public void receiveQueue(String text) {
        System.out.println(text);
    }
}

JmsListener是spring-jms提供的一个注解,会实例化一个Jms的消息监听实例,也就是一个异步的消费者。

添加JMS的注解扫描

@SpringBootApplication
@EnableJms
public class ActivemqDemoApplication {
    @Bean
    public Queue queue() {
        return new ActiveMQQueue("sample.queue");
    }

    public static void main(String[] args) {
        SpringApplication.run(ActivemqDemoApplication.class, args);
    }
}

@EnableJms会启动jms的注解扫描,相当于<jms:annotation-d riven/>

启动项目

在ActivemqDemoApplication启动java工程。
这里写图片描述

然后在浏览器输入:http://localhost:8080/sendMsg?msg=HelloActiveMQ

就可以看到eclipse的控制台输出了对应的消息。

连接外部的ActiveMQ

修改配置

官方的实例用的是in-memory的ActiveMQ。然而我们实际使用的时候都是连接外部共用的ActiveMQ服务。所以,我们修改一下配置,来使用外部的ActiveMQ服务。

spring.activemq.broker-url=tcp://localhost:61616
#spring.activemq.broker-url=failover:(tcp://localhost:61616,tcp://localhost:61617)
spring.activemq.close-timeout=5000
spring.activemq.in-memory=false
#spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=100
spring.activemq.send-timeout=3000

这里被注释掉的spring.activemq.broker-url是对应ActiveMQ集群时候的broker-url配置。

spring.activemq.pool.enabled备注释掉了,是因为作者用的spring boot 1.5.6对应的jms-starter没有包含activemq-pool的依赖引入,所以不能设置pool.enabled=true,如果要使用需要自己添加activemq-pool的依赖包:

<dependency>
   <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-pool</artifactId>
   <!--  <version>5.7.0</version> -->
</dependency>

启动服务

当我们没有启动ActiveMQ的时候,spring boot启动失败了:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field jmsMessagingTemplate in com.example.demo.activemq.Producer required a bean of type 'org.springframework.jms.core.JmsMessagingTemplate' that could not be found.
    - Bean method 'jmsMessagingTemplate' not loaded because Ancestor org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration did not match


Action:

Consider revisiting the conditions above or defining a bean of type 'org.springframework.jms.core.JmsMessagingTemplate' in your configuration.

但是失败的消息提示很诡异,告诉的是找不到JmsMessagingTemplate,而不是提示连接不上ActiveMQ。。。

按照提示信息里面说的设置debug=true,能够打印出auto-configure中相关类的匹配信息,但是仍然不能直接定位到是ActiveMQ服务连接不上。

如果遇到上述问题,可以尝试检查ActiveMQ服务是否能够连接。

一个jmsTemplate支持queue和topic

作者使用的版本已经支持一个jmsTemplate支持queue和topic的消息发送,只需要指定不同的destination即可。

但是消息的接收,也就是@JmsListener如果不指定独立的containerFactory的话是只能消费queue消息的,如果要能够同时接收topic消息,需要给topic对应的@JmsListener增加containerFactory配置:

    //需要给topic定义独立的JmsListenerContainer
    @Bean
    public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ConnectionFactory activeMQConnectionFactory) {
        DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
        bean.setPubSubDomain(true);
        bean.setConnectionFactory(activeMQConnectionFactory);
        return bean;
    }


    @JmsListener(destination = "sample.topic", containerFactory="jmsListenerContainerTopic")
    public void receiveTopic(String text) {
        System.out.println(text);
    }

本文的项目代码已经上传到spring-boot-activemq-demo

已标记关键词 清除标记
相关推荐
错误信息如下: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.amqp.rabbit.config.ListenerContainerFactoryBean#0': Invocation of init method failed; nested exception is java.lang.NullPointerException at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1630) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:742) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:634) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:682) at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:553) at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:494) at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:171) at javax.servlet.GenericServlet.init(GenericServlet.java:160) at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1280) at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1193) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1088) at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5176) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5460) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.NullPointerException at org.springframework.amqp.rabbit.config.ListenerContainerFactoryBean.createContainer(ListenerContainerFactoryBean.java:533) at org.springframework.amqp.rabbit.config.ListenerContainerFactoryBean.createInstance(ListenerContainerFactoryBean.java:411) at org.springframework.amqp.rabbit.config.ListenerContainerFactoryBean.createInstance(ListenerContainerFactoryBean.java:61) at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:134) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1688) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1626) ... 28 more xml配置 如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd" default-lazy-init="false"> <!-- rabbitmq连接工厂 --> <rabbit:connection-factory id="connectionFactory" username="${mq.username}" password="${mq.password}" host="${mq.host}" port="${mq.port}" virtual-host="${mq.vhost}"/> <rabbit:admin connection-factory="connectionFactory"/> <!-- 定义rabbitmq服务 --> <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter"/> <!-- 使用fastjson进行类型转换 --> <bean id="jsonMessageConverter" class="com.util.FastJsonMessageConverter"/> <!-- 定义队列 --> <rabbit:queue name="order.queue" durable="true" auto-delete="false" exclusive="false"/> <!-- 定义路由并绑定队列 --> <rabbit:direct-exchange name="order.exchange" auto-delete="false" durable="true"> <rabbit:bindings> <rabbit:binding queue="order.queue" key="order"></rabbit:binding> </rabbit:bindings> </rabbit:direct-exchange> <!-- 定义监听器 ack为自动删除模式 --> <rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto" > <rabbit:listener ref="orderQueueListener" queues="order.queue"/> </rabbit:listener-container> <bean name="orderQueueListener" class="com.mq.OrderQueueListener"/> </beans> 我目前定位出是:OrderQueueListener这个类应该没有被初始化导致的。 但找不出解决办法
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页