• ActiveMQ 入门和与 Spring 整合


    ActiveMQ

    入门演示

    activemq 依赖

    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-client</artifactId>
        <version>5.13.4</version>
    </dependency>
    
    Caused by: java.io.IOException: Transport scheme NOT recognized: [http]
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("http://192.168.20.131:61616");
    
    Could not connect to broker URL: tcp://192.168.20.131:61616. Reason: java.net.ConnectException: Connection timed out: connect
    

    消息传递方式 1. 点对点 2. 发布订阅

    点对点

    用消息队列实现,如果没有消费者,则消息会先存到消息队列中。一个消息只会被一个消费者消费。

    package com.mozq;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    import javax.jms.*;
    
    public class QueueProducer {
    
        public static void main(String[] args) throws JMSException {
            //创建连接工厂
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.20.131:61616");
            //获取连接
            Connection connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //获取会话
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建队列
            Queue queue = session.createQueue("test_queue");
            //创建生产者
            MessageProducer producer = session.createProducer(queue);
            //创建消息
            TextMessage message = session.createTextMessage("欢迎来到消息中间件世界");
            //发送
            for (int i = 0; i < 5; i++) {
                producer.send(message);
            }
            //关闭资源
            producer.close();
            session.close();
            connection.close();
        }
    
    }
    
    消费者可以调用重发方法进行消息的重发。次数和延迟。

    RedeliveryPolicy session.recover()

    package com.mozq;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    import org.apache.activemq.RedeliveryPolicy;
    
    import javax.jms.*;
    import java.io.IOException;
    
    public class QueueConsumer {
    
        private static  int i = 0;
    
        public static void main(String[] args) throws JMSException, IOException {
            //创建连接工厂
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.20.131:61616");
    
            //重发策略
            RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
            redeliveryPolicy.setMaximumRedeliveries(2);
            redeliveryPolicy.setRedeliveryDelay(3000);
    
            ((ActiveMQConnectionFactory) connectionFactory).setRedeliveryPolicy(redeliveryPolicy);
            //获取连接
            Connection connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //获取会话
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建队列
            Queue queue = session.createQueue("test_queue");
            //创建消费者
            MessageConsumer consumer = session.createConsumer(queue);
            //监听消息
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    TextMessage textMessage = (TextMessage) message;
                    try {
                        System.out.println(i++ + "消息处理");
                        int i = 1 / 0;
                        System.out.println("处理完成");
                        System.out.println(textMessage.getText());
                    } catch (Exception e) {
                        System.out.println("处理失败");
                        try {
                            session.recover();
                        } catch (JMSException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
            });
            System.in.read();
            //关闭资源
            session.close();
            connection.close();
        }
    
    }
    

    发布订阅

    发布者发布消息时,如果没有消费者,则这个消息不会被消费。发布消息时一条消息会被所有已激活的消费者消费。

    package com.mozq;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    import javax.jms.*;
    
    public class TopicProducer {
    
        private static final String url = "tcp://192.168.20.131:61616";
        private static final String topicName = "test_topic";
    
        public static void main(String[] args) throws JMSException {
            //创建连接工厂
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
            //获取连接
            Connection connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //获取会话
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建主题
            Topic topic = session.createTopic(topicName);
            //创建生产者
            MessageProducer producer = session.createProducer(topic);
            //创建消息
            TextMessage message = session.createTextMessage("欢迎来到消息中间件世界,主题消息");
            //发送
            for (int i = 0; i < 5; i++) {
                producer.send(message);
            }
            //关闭资源
            producer.close();
            session.close();
            connection.close();
        }
    }
    
    
    package com.mozq;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    import javax.jms.*;
    import java.io.IOException;
    
    public class QueueConsumer {
    
        public static void main(String[] args) throws JMSException, IOException {
            //创建连接工厂
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.20.131:61616");
            //获取连接
            Connection connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //获取会话
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建队列
            Queue queue = session.createQueue("test_queue");
            //创建消费者
            MessageConsumer consumer = session.createConsumer(queue);
            //监听消息
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    TextMessage textMessage = (TextMessage) message;
                    try {
                        System.out.println(textMessage.getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });
            System.in.read();
            //关闭资源
            session.close();
            connection.close();
        }
    
    }
    
    package com.mozq;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    
    import javax.jms.*;
    import java.io.IOException;
    
    public class TopicConsumer {
    
        private static final String url = "tcp://192.168.20.131:61616";
        private static final String topicName = "test_topic";
    
        public static void main(String[] args) throws JMSException, IOException {
            //创建连接工厂
            ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
            //获取连接
            Connection connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //获取会话
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建主题
            Topic topic = session.createTopic(topicName);
            //创建消费者
            MessageConsumer consumer = session.createConsumer(topic);
            //监听消息
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    TextMessage textMessage = (TextMessage) message;
                    try {
                        System.out.println(textMessage.getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });
            System.in.read();
            //关闭资源
            session.close();
            connection.close();
        }
    
    }
    

    Spring 整合 ActiveMQ

    spring-jms 依赖

    <properties>
        <spring.version>4.2.4.RELEASE</spring.version>
    </properties>
    
    <dependencies>
        <!-- activemq 相关 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-client</artifactId>
            <version>5.13.4</version>
        </dependency>
        <!-- 测试相关 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
        </dependency>
    </dependencies>
    

    点到点

    spring-jms-producer 配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jms="http://www.springframework.org/schema/jms"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/context
                               http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="cn.itcast.demo"></context:component-scan>
    
        <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
        <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
            <property name="brokerURL" value="tcp://192.168.20.131:61616" />
        </bean>
    
        <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
        <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
            <property name="targetConnectionFactory" ref="targetConnectionFactory" />
        </bean>
    
        <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
        <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
            <property name="connectionFactory" ref="connectionFactory" />
        </bean>
    
        <!--点对点-->
        <bean id="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
            <constructor-arg value="queue_text" />
        </bean>
    
        <!-- 发布订阅 -->
        <bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
            <constructor-arg value="topic_text" />
        </bean>
    
    </beans>
    
    package cn.itcast.demo;
    
    import org.apache.activemq.command.ActiveMQQueue;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.jms.core.MessageCreator;
    import org.springframework.stereotype.Component;
    
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.Session;
    
    @Component
    public class QueueProducer {
    
        @Autowired
        private JmsTemplate jmsTemplate;
    
        @Autowired
        private ActiveMQQueue queueTextDestination;
    
        public void sendTextMessage(String message){
            jmsTemplate.send(queueTextDestination, new MessageCreator() {
                @Override
                public Message createMessage(Session session) throws JMSException {
                    return session.createTextMessage(message);
                }
            });
        }
    }
    
    
    package cn.itcast.demo;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:spring-jms-producer.xml")
    public class QueueProducerTest {
    
        @Autowired
        private QueueProducer queueProducer;
    
        @Test
        public void testSend(){
            queueProducer.sendTextMessage("spring-jms 队列消息");
        }
    }
    

    spring-jms-consumer 配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:jms="http://www.springframework.org/schema/jms"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    		http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context
    		http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="cn.itcast.demo" />
    
        <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
        <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
            <property name="brokerURL" value="tcp://192.168.20.131:61616" />
        </bean>
    
        <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
        <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
            <property name="targetConnectionFactory" ref="targetConnectionFactory" />
        </bean>
    
        <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
        <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
            <property name="connectionFactory" ref="connectionFactory" />
        </bean>
    
            <!--点对点-->
        <bean id="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
            <constructor-arg value="queue_text" />
        </bean>
    
        <!-- 发布订阅 -->
        <bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
            <constructor-arg value="topic_text" />
        </bean>
    
        <!-- 消息监听实现类 -->
        <bean id="myTextMessageListener" class="cn.itcast.demo.MyTextMessageListener" />
    
        <!-- 消息监听容器 -->
        <bean id="defaultMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="connectionFactory" />
            <property name="destination" ref="queueTextDestination" />
            <property name="messageListener" ref="myTextMessageListener" />
        </bean>
        
    </beans>
    

    监听类

    package cn.itcast.demo;
    
    import org.springframework.stereotype.Component;
    
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageListener;
    import javax.jms.TextMessage;
    
    @Component
    public class MyTextMessageListener implements MessageListener {
    
        @Override
        public void onMessage(Message message) {
            if(message instanceof TextMessage){
                TextMessage textMessage = (TextMessage) message;
                try {
                    String text = textMessage.getText();
                    System.out.println(text);
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    
    package cn.itcast.demo;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import java.io.IOException;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:spring-jms-consumer.xml")
    public class QueueConsumerTest {
    
        @Test
        public void test(){
            try {
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    发布订阅

    发布

    package cn.itcast.demo;
    
    import org.apache.activemq.command.ActiveMQQueue;
    import org.apache.activemq.command.ActiveMQTopic;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.jms.core.MessageCreator;
    import org.springframework.stereotype.Component;
    
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.Session;
    
    @Component
    public class TopicProducer {
    
        @Autowired
        private JmsTemplate jmsTemplate;
    
        @Autowired
        private ActiveMQTopic topicTextDestination;
    
        public void sendTextMessage(String message){
            jmsTemplate.send(topicTextDestination, new MessageCreator() {
                @Override
                public Message createMessage(Session session) throws JMSException {
                    return session.createTextMessage(message);
                }
            });
        }
    }
    
    package cn.itcast.demo;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:spring-jms-producer.xml")
    public class TopicProducerTest {
    
        @Autowired
        private TopicProducer topicProducer;
    
        @Test
        public void testSend(){
            topicProducer.sendTextMessage("spring-jms 主题消息");
        }
    }
    

    订阅

    <!-- 发布订阅的目的地 -->
    <bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic_text" />
    </bean>
    
    <!-- 消息监听实现类 -->
    <bean id="myTextMessageListener" class="cn.itcast.demo.MyTextMessageListener" />
    
    <!-- 消息监听容器 -->
    <bean id="defaultMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="topicTextDestination" />
        <property name="messageListener" ref="myTextMessageListener" />
    </bean>
    

    消息监听器实现方法和点对点模式的相同。

    activemq 使用思路

    遵循 jms 规范

    2种消息传递方式

    1. queue 点到点方式 一个消息只会被消费一次
    2. topic 发布订阅方式 一个消息被多个消费者消费

    5种消息类型

    TextMessage

    ObjectMessage

    MapMessage

    BytesMessage

    StreamMessage

    mq 的使用场景:

    ​ 完成系统间的解耦。消费者调用生产者的代码时不需要生产者返回结果。

    用户注册,发送验证邮件。
    商品审核,生成静态页面,更新 solr 数据。
    

    spring 和 activemq 整合思路

    1. 生产者 (JmsTemplate)

    JmsTemplate 需要注入一个 Spring 提供的连接工厂, 这个连接工厂需要一个 activemq 的连接工厂,同时使用 JmsTemplate 发送消息时,需要传入 Destination 。

    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://192.168.20.131:61616" />
    </bean>
    
    <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
    <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
        <property name="targetConnectionFactory" ref="targetConnectionFactory" />
    </bean>
    
    <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
    </bean>
    
    <!--点对点-->
    <bean id="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg value="queue_text" />
    </bean>
    
    <!-- 发布订阅 -->
    <bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic_text" />
    </bean>
    
    1. 消费者 (DefaultMessageListenerContainer)

    消息监听容器需要,1. 消息监听器,2. spring 的连接工厂, 而 spring 的连接工厂又需要 activemq 提供的连接工厂,3. 目标 Destination 。消息的处理在消息监听器中,spring 启动时将会自动创建连接,当消息被接收时监听方法被自动调用。

    <!-- 消息监听容器   生成页面 -->
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="topicPageDeleteDestination" />
        <property name="messageListener" ref="pageDeleteListener" />
    </bean>
    

    问题

    org.springframework.jms.connection.ConnectionFactoryUtils.releaseConnection(ConnectionFactoryUtils.java:83)Could not close JMS Connection
    org.apache.activemq.ConnectionFailedException: The JMS connection has failed: java.io.EOFException
    原因:
    	重启下服务好了。
    
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'temListImportMessageListenerContainer' defined in file [D:CodeIdeaProjectIdeaCodepinyougou-workpinyougou-parentpinyougou-search-service	argetclassesspringapplicationContext-jms.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
    PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'messageListener' threw exception; nested exception is java.lang.IllegalArgumentException: Message listener needs to be of type [javax.jms.MessageListener] or [org.springframework.jms.listener.SessionAwareMessageListener]
    原因:
    	没有实现 MessageListener 接口。
    
    org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; 
    Caused by: org.apache.activemq.ConnectionFailedException: The JMS connection has failed: java.io.EOFException
    原因:
    	重启下服务好了。
    
  • 相关阅读:
    [转]修改远程桌面端口
    [转]3个著名加密算法(MD5、RSA、DES)的解析
    [转]常见HTTP状态(如200,304,404,503)
    用 SqlConnectionStringBuilder 来写连接字符串,向连接字符串添加设置
    windows 设置ipsec防火墙
    网络带宽单位换算
    Linux 检查端口gps命令
    设置Linux防火墙
    windows 服务器同步互联网时间
    windows 路由转发
  • 原文地址:https://www.cnblogs.com/mozq/p/11306753.html
Copyright © 2020-2023  润新知