Spring、Spring Boot整合Active MQ

  • 通过Spring以及Spring Boot使得Active MQ的发送以及接收更加简单。更多的对象通过自动配置、自动注入的方式进入到IOC容器中,而我们只需要在容器中加入一些我们个性化定制的内容,比如说要发送的消息、监听器的行为等,就可以让实现自己的想要的功能。

1. Spring整合Active MQ

1.1 引入依赖

<!-- activemq核心依赖包  -->
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.15.9</version>
</dependency>
<!-- activemq连接池 -->
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-pool</artifactId>
    <version>5.15.9</version>
</dependency>
<!--spring相关依赖包-->
<dependency>
    <groupId>org.apache.xbean</groupId>
    <artifactId>xbean-spring</artifactId>
    <version>4.15</version>
</dependency>
<!-- Spring核心依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>

1.2 Spring的配置文件

  • 开启组件扫描
    <context:component-scan base-package="ltd.dujiabao.activemq.spring.*"/>
    
  • 配置ConnectionFactory将它放进一个池子里面
    <!--  相当于拿到一个ConnectionFactory,还放进了一个池里面  -->
    <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
        <property name="connectionFactory">
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">
                <property name="brokerURL" value="tcp://192.168.233.134:61616"/>
            </bean>
        </property>
    </bean>
    
  • 自己定制一个目的地,可以是queue,也可以是topic。并为该目的地定义一个名称。
    <!--  实例化一个queue的目的地,并命名为`spring-active-queue`  -->
    <bean id="destinationQueue" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg index="0" value="spring-active-queue"/>
    </bean>
    
    <!--  实例化一个topic的目的地,并命名为`spring-active-topic`  -->
    <bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg index="0" value="spring-active-topic"/>
    </bean>
    
  • 配置一个JmsTemplate,它将创建Producer、Consumer、Message的工作、发送消息、注入目的地、接受并转换消息的工作封装在里面。对外留一个定义Message的接口。简化了发送消息、接受消息的流程。
        <!--  类似于一个生产者或者消费者的角色  -->
        <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
            <property name="connectionFactory" ref="connectionFactory"/>
    <!--        <property name="defaultDestination" ref="destinationQueue"/>-->
            <property name="defaultDestination" ref="destinationTopic"/>
            <property name="messageConverter">
                <bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
            </property>
        </bean>
    
  • 至此,简单的配置已完成。

1.3 生产者

  • 很简单,直接调用jmsTemplatesend方法即可。
  • 因此,首先自动注入jmsTemplate,然后自己写一个方法调用它的send方法
  • 总的来说,这个生产者的代码,无关目的地类型,因为配置目的地的工作在配置文件中完成。
    @Service
    public class ActiveMQProducer {
      @Autowired
      private JmsTemplate jmsTemplate;
    
      /**
       * 也就是说, 只要生产一个消息就好,其他的事,不用自己管。
       *
       * @param text
       */
      public void sendText(String text) {
        jmsTemplate.send((session) -> session.createTextMessage(text));
        System.out.println("发送消息:" + text + " 成功");
      }
    }
    

    其中,send方法需要传入一个MessageCreator的实现类,也就是将内容返回到一个通过Session创建的Message中,这里通过简单的lambda表达式实现。

  • MessageCreator
    @FunctionalInterface
    public interface MessageCreator {
      Message createMessage(Session var1) throws JMSException;
    }
    

1.4 消费者

  • 消费者和上面的用法基本一致,通过JmsTemplate,接收Message里面的内容。JmsTemplate 会提前将Message的消息体转换出来。
    @Service
    public class ActiveMQConsumer {
      @Autowired
      JmsTemplate jmsTemplate;
    
      public String recieveText() {
        Object o = jmsTemplate.receiveAndConvert();  // 接收并转换
        if (o instanceof String) {
          String text = (String) o;
          System.out.println("收到消息: " + text);
          return text;
        } else return null;
      }
    }
    
  • 当然,也可以配置一个监听器,使得接收到信息之后,自动触发。
    @Component
    public class MyMessageListener implements MessageListener {
      @Override
      public void onMessage(Message message) {
        if (message instanceof TextMessage) {
          TextMessage textMessage = (TextMessage) message;
          try {
            System.out.println("收到了一条TextMessage" + textMessage.getText());
          } catch (JMSException e) {
            e.printStackTrace();
          }
        }
      }
    }
    
    <!--  配置一个监听器  -->
    <bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="destinationTopic"/>
        <property name="messageListener" ref="myMessageListener"/>
    </bean>
    

1.5 队列和主题

  • 对于队列和主题,只需要简单的在配置文件中修改目的地,以及目的地注入的对象属性,就可以修改。代码方面没有太多需要修改的地方。

2. Spring Boot整合Active MQ

  • 其实跟刚刚的用法一致,只是进一步简略了。

2.1 pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>org.example</groupId>
    <artifactId>mq-springboot</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--spring boot整合activemq的jar包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
            <version>2.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.2 配置文件

  • 配置文件主要配置MQ的地址端口号。以及目的地的类型。最后自定义了两个名称,在java文件中可以取出来,作为目的地的名称。
    # web占用的端口
    server:
      port: 7777
    
    spring:
      activemq:
        # activemq的broker的url
        broker-url: tcp://192.168.233.134:61616
        # 连接activemq的broker所需的账号和密码
        user: admin
        password: admin
      jms:
        # 目的地是queue还是topic, false(默认) = queue    true =  topic
    #    pub-sub-domain: true
        pub-sub-domain: true
    
    #  自定义队列名称。这只是个常量
    myqueue: boot-activemq-queue
    clocktopic: boot-ctivemq-clock-queue
    

2.3 使用

  • 在Spring Boot中,大部分配置都不需要了,只需要个性化配置一个自己的目的地即可。其中,在设置目的地名字的时候,就通过@Value注解将配置文件的内容注入。至此,目的地已进入IOC容器中。
    @Configuration
    @EnableJms  // 允许使用JMS
    @EnableScheduling  // 允许开启定时任务调度
    public class ConfigBean {
      @Value("${myqueue}")
      private String myQueueName;
      @Value("${clocktopic}")
      private String clockTopicName;
    
    
      @Bean
      public Destination destination() {
        return new ActiveMQQueue(myQueueName);// 目的地为队列
        //return new ActiveMQTopic(myQueueName);  // 目的地为主题
      }
    
      @Bean
      public Topic clockTopic() {
        return new ActiveMQTopic(clockTopicName);
      }
    }
    
  • 生产者代码。在Spring的时候,使用了JmsTemplate,需要实例化MessateCreator,还需要指定生成什么样的Message。而如今,使用JmsMessagingTemplate就更加方便了。实际上,JmsMessagingTemplate内部有一个属性就是JmsTemplate,在内部它可以判断传入的Object类型,从而创建相对应的Message类型。
    @Service
    public class ActiveMQProducer {
      @Autowired
      JmsMessagingTemplate jmsMessagingTemplate;
    
      @Qualifier(value = "destination")
      @Autowired
      Destination destination;
    
      @Qualifier(value = "clockTopic")
      @Autowired
      Topic clockTopic;
    
      public void produceMessage(Object obj) {
        jmsMessagingTemplate.convertAndSend(destination, obj);
      }
    
      /**
       * 一个时钟定时器,发送消息
       */
      @Scheduled(fixedDelay = 1000)
      public void produceMessageScheduled() {
        jmsMessagingTemplate.convertAndSend(clockTopic, LocalTime.now().toString());
      }
    }
    

在这里插入图片描述在这里插入图片描述

  • 消费者代码。如今写监听器就更加简单了,直接在方法上面标注一个@JmsListener注解,就可以注册某个名称的目的地的监听器,从而在消息进入之后,自动匹配方法的入参。
    @Slf4j
    @Component
    public class ActiveMQConsumer {
      ///**
      // * 写了一个TextMessage监听器
      // *
      // * @param textMessage
      // * @throws JMSException
      // */
      //@JmsListener(destination = "${myqueue}")
      //public void receiveText(TextMessage textMessage) throws JMSException {
      //  String text = textMessage.getText();
      //  log.info("接收到TextMessage信息:" + text);
      //}
    
      @JmsListener(destination = "${myqueue}")
      public void receiveText(Message message) throws JMSException {
        if (message instanceof TextMessage) {
          TextMessage textMessage = (TextMessage) message;
          log.info("接收到一个TextMessage:" + textMessage.toString());
        }
    
        if (message instanceof MapMessage) {
          MapMessage mapMessage = (MapMessage) message;
          log.info("接收到一个MapMessage:" + mapMessage.toString());
        }
      }
    
      @JmsListener(destination = "${clocktopic}")
      public void receiveTime(TextMessage textMessage) throws JMSException {
        log.info("当前时间是::" + textMessage.getText());
      }
    }
    

    这种方法,就很像处理请求的注解@RequestMapping

  • 写一个定时定间隔发送消息的生产者,首先需要在配置类上面加一个注解
    @EnableScheduling  // 允许开启定时任务调度
    
    然后在在方法上面添加注解,表示时间间隔(毫秒级别)
      @Scheduled(fixedDelay = 1000)
      public void produceMessageScheduled() {
        jmsMessagingTemplate.convertAndSend(clockTopic, LocalTime.now().toString());
        //jmsTemplate.send(clockTopic, (session) -> session.createTextMessage(LocalTime.now().toString()));
      }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值