ActiveMQ 整合 Spring

  首先说一下我们的需求:一个添加商品和一个搜索商品功能,搜索功能我们使用了Solr索引库进行索引,所以当我们添加一个商品时就应该将此商品添加到索引库。如果不是用JMS,添加商品模块就需要依赖搜索商品模块,这样形成了耦合关系,项目启动顺序也会存在问题,所以我们采用了ActiveMQ来实现添加商品和搜索商品模块之间的通信,解决了耦合问题。当我们添加商品时就给服务器发送添加商品的消息(可将商品id发送给服务器),搜索商品监听到该消息,就去执行添加索引库的操作。


【消息发送方】

第一步:引入相关jar包
这里写图片描述
这里写图片描述
这里写图片描述

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jms</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
</dependency>

第二步:配置Activemq整合spring。配置:ConnectionFactory;生产者,使用JMSTemplate对象,发送消息;Destination

    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://192.168.20.216:61616" />
    </bean>
    <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
    <bean id="connectionFactory"
        class="org.springframework.jms.connection.SingleConnectionFactory">
        <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
        <property name="targetConnectionFactory" ref="targetConnectionFactory" />
    </bean>
    <!-- 配置生产者 -->
    <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
        <property name="connectionFactory" ref="connectionFactory" />
    </bean>
    <!--这个是队列目的地,点对点的 -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg>
            <value>spring-queue</value>
        </constructor-arg>
    </bean>
    <!--这个是主题目的地,一对多的 -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg>
            <value>itemAddTopic</value>
        </constructor-arg>
    </bean>

第三步:测试:
  因为项目启动时已经初始化spring容器了,只需从容器中获得JMSTemplate对象和一个Destination对象,因为使用JMSTemplate对象发送消息,需要知道Destination

@Autowired
private JmsTemplate jmsTemplate;
@Resource
private Destination topicDestination;

@Override
public E3Result addItem(TbItem item, String desc) {
    //生成商品id
    final long itemId = IDUtils.genItemId();
    //向商品表添加数据
    itemMapper.insert(item);

    //发送商品添加消息
    jmsTemplate.send(topicDestination, new MessageCreator(){
        @Override
        public Message createMessage(Session session) throws JMSException {
            TextMessage textMessage =session.createTextMessage(itemId+"");              
            return textMessage;
        }           
    });
    //返回成功      
    return E3Result.ok();
}

【消息接受者】

第一步:相关配置如上面的第一步
第二步:配置Activemq整合spring。配置:ConnectionFactory;Destination;监听的消息;监听器Listener

    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://192.168.20.216:61616" />
    </bean>
    <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
    <bean id="connectionFactory"
        class="org.springframework.jms.connection.SingleConnectionFactory">
        <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
        <property name="targetConnectionFactory" ref="targetConnectionFactory" />
    </bean>

    <!--这个是队列目的地,点对点的 -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg>
            <value>spring-queue</value>
        </constructor-arg>
    </bean>
    <!--这个是主题目的地,一对多的 -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="itemAddTopic" />
    </bean>

    <!-- 接收消息 -->
    <!-- 监听商品添加消息,同步索引库 -->
    <bean id="itemAddMessageListener" class="cn.e3mall.search.message.ItemAddMessageListener"/>
    <!-- 消息监听器 -->
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="topicDestination" />
        <property name="messageListener" ref="itemAddMessageListener" />
    </bean>

第三步:配置监听的消息
  其中接受者在程序启动时就要一直监听,所以要写一个实现MessageListener接口的类,写成Bean交给spring容器管理,使其向启动时就在监听,当监听到消息时就进行一系列想要进行的操作,如我们本系统当监听到有商品添加时,就去同步索引库,代码如下:

public class ItemAddMessageListener implements MessageListener{

    @Autowired
    private ItemMapper itemMapper;
    @Autowired
    private SolrServer solrServer;

    @Override
    public void onMessage(Message message) {
        // 从消息中取商品id
        TextMessage textMessage =(TextMessage)message;
        String text;
        try {
            text = textMessage.getText();
            Long itemId = new Long(text);
            //等待事物提交
            Thread.sleep(1000);
            //根据商品id查询商品信息
            SearchItem searchItem = itemMapper.getItemById(itemId);
            //创建一个文档对象
            SolrInputDocument document = new SolrInputDocument();
            //向文档对象中添加域
            document.addField("id", searchItem.getId());
            。。。
            //把文档写入索引库
            solrServer.add(document);
            //提交
            solrServer.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  因为发送消息是个很快的过程,此时可能商品还没添加到数据库中,所以可能存在根据id去查询数据库时查不到,我们采用的办法就是,等待事物提交:Thread.sleep(1000);,然后再去查询数据库

猜你喜欢

转载自blog.csdn.net/wrs120/article/details/80501918