ActiveMQ in message middleware: spring boot integrates ActiveMQ

Keywords: Netty Spring Apache SpringBoot

Less nonsense, more dry goods:

integration

  1. Create an initialization project for springboot
    Slightly (this can be done)
  2. pom.xml is introduced as follows:
    Note: I use 5.15.11 here, so the imported package should also be the latest 5.15.11
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
            <version>2.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
            <version>5.15.11</version>
        </dependency>
  1. application.yml is configured as follows:
spring:
  activemq:
    # mq communication address
    broker-url: tcp://39.96.70.45:61616
    # Whether memory mode is enabled (that is, MQ is not installed, and an MQ instance is started at the same time when the project is started)
    in-memory: false
    pool:
      # Whether to open the connection pool? The connection pool using ActiveMQ needs to introduce ActiveMQ pool dependency
      # When true, the required a bean of type 'org.springframework.jms.core.JmsMessagingTemplate' that could not be found. Exception will be reported. At the end of the article, there is a solution.
      enabled: false
      # Idle connection expiration time, default is 30 seconds
      idle-timeout: 30000
      # Connection pool maximum connections
      max-connections: 10
  1. The startup class is annotated as follows:
    @Enable JMS: declare support for JMS annotations
@EnableJms
@SpringCloudApplication
public class DemoApplication {
	    public static void main(String[] args) {
        SpringApplication.run(DemoApplication .class, args);
    }
}
  1. Establish activeMQ configuration class ActiveMqConfig.java
package com.jifang.netty.config;

import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.jms.Queue;

/**
 * ActiveMq To configure
 *
 * @author wangdy
 * @date 2020/2/7 15:15
 */
@Configuration
public class ActiveMqConfig {
	/**
	 * Define the queue for messages
	 */
	@Bean
	public Queue queue() {
		return new ActiveMQQueue("chat-queue");
	}
}
  1. Production and sending messages
package com.jifang.netty.service.impl;

import cn.hutool.json.JSONUtil;
import com.jifang.netty.enums.MsgActionTypeEnum;
import com.jifang.netty.enums.MsgTypeEnum;
import com.jifang.netty.service.MessageService;
import com.jifang.netty.service.MqMessageService;
import com.jifang.netty.utils.JsonUtil;
import com.jifang.netty.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Service;

import javax.jms.Queue;

/**
 * @author wangdy
 * @date 2020/2/7 15:21
 */
@Service
public class MqMessageServiceImpl implements MqMessageService {
	@Autowired
	private Queue queue;
	@Autowired
	private JmsMessagingTemplate jmsMessagingTemplate;
	@Autowired
	private MessageService messageService;

	/**
		send message
	*/
	@Override
	public void sendMessage(String message) {
		// Method 1: add a message to the message queue
		jmsMessagingTemplate.convertAndSend(queue, message);
		// Method 2: in this way, you do not need to create a queue manually. The system will create a queue named testQueue by itself
		// jmsMessagingTemplate.convertAndSend("testQueue", message);
	}

	/**
		Consumer News
	*/
	@Override
	@JmsListener(destination = "chat-queue")// Use JmsListener to configure the queues consumers listen to, where message is the received message
	public void handleMessage(String message) {
		System.out.println("Received successfully: message" + message);
	}
}

pit

The above setting pool.enabled=true will result in an error. By looking at the source code, it is found that because the version of springboot here uses 2.1.x, the default is @ conditionalonclass ({jmspoolconnectionfactory. Class, pooledobject. Class}). The source code is as follows:
JmsPoolConnectionFactory

@Configuration
@ConditionalOnMissingBean(ConnectionFactory.class)
class ActiveMQConnectionFactoryConfiguration {

    @Configuration
    @ConditionalOnClass(CachingConnectionFactory.class)
    @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true)
    static class SimpleConnectionFactoryConfiguration {

        private final JmsProperties jmsProperties;

        private final ActiveMQProperties properties;

        private final List<ActiveMQConnectionFactoryCustomizer> connectionFactoryCustomizers;

        SimpleConnectionFactoryConfiguration(JmsProperties jmsProperties,
                ActiveMQProperties properties,
                ObjectProvider<ActiveMQConnectionFactoryCustomizer> connectionFactoryCustomizers) {
            this.jmsProperties = jmsProperties;
            this.properties = properties;
            this.connectionFactoryCustomizers = connectionFactoryCustomizers
                    .orderedStream().collect(Collectors.toList());
        }

        @Bean
        @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "true", matchIfMissing = true)
        public CachingConnectionFactory cachingJmsConnectionFactory() {
            JmsProperties.Cache cacheProperties = this.jmsProperties.getCache();
            CachingConnectionFactory connectionFactory = new CachingConnectionFactory(
                    createConnectionFactory());
            connectionFactory.setCacheConsumers(cacheProperties.isConsumers());
            connectionFactory.setCacheProducers(cacheProperties.isProducers());
            connectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize());
            return connectionFactory;
        }

        @Bean
        @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false")
        public ActiveMQConnectionFactory jmsConnectionFactory() {
            return createConnectionFactory();
        }

        private ActiveMQConnectionFactory createConnectionFactory() {
            return new ActiveMQConnectionFactoryFactory(this.properties,
                    this.connectionFactoryCustomizers)
                            .createConnectionFactory(ActiveMQConnectionFactory.class);
        }

    }

 // Note: import org.messaginghub.pooled.jms.JmsPoolConnectionFactory is used here;
    @Configuration
    @ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class })
    static class PooledConnectionFactoryConfiguration {

        @Bean(destroyMethod = "stop")
        @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "true", matchIfMissing = false)
        public JmsPoolConnectionFactory pooledJmsConnectionFactory(
                ActiveMQProperties properties,
                ObjectProvider<ActiveMQConnectionFactoryCustomizer> factoryCustomizers) {
            ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
                    properties,
                    factoryCustomizers.orderedStream().collect(Collectors.toList()))
                            .createConnectionFactory(ActiveMQConnectionFactory.class);
            return new JmsPoolConnectionFactoryFactory(properties.getPool())
                    .createPooledConnectionFactory(connectionFactory);
        }
    }
}

So the solution:
Replace the original ActiveMQ pool with: pooled JMS
Note: many places on the Internet say that springboot2.0.x does not have this problem. I didn't study it in detail. You can see the source code if you are interested.

<!--  <dependency>
       <groupId>org.apache.activemq</groupId>
       <artifactId>activemq-pool</artifactId>
       <version>5.15.11</version>
   </dependency>-->
<dependency>
    <groupId>org.messaginghub</groupId>
    <artifactId>pooled-jms</artifactId>
</dependency>

test

Run the program, call the method to send the message, you can see the changes of the queue message, and the log printed by the console to receive the message.
As shown in the following figure: the number of queues in and out has been

84 original articles published, 200 praised, 200000 visitors+
Private letter follow

Posted by miltonos on Wed, 12 Feb 2020 07:37:00 -0800