Message Middleware Series 6, rabbit and spring Integrated Practice

Keywords: Java Spring xml RabbitMQ

Foreword: This is one of the articles in middleware series. Friends in need can see other articles in this series.
Message Middleware Series I. Basic Understanding of Message Middleware
Message Middleware Series II. Installation of ActeMQ and Rabbit MQ under Windows
Simple Use of Message Middleware Series 3, JMS and ActeMQ
Message Middleware Series IV. Understanding the Simple Use of AMQP and RabbiyMq
Message Middleware Series V. rabbit Message Recognition Mechanism
Message Middleware Series 6, Rabbit and Spring Integrated Practice
At present, it is still in the process of continuous updating. Please look forward to it.

This project is a practical learning project integrated with rabbit and spring. It simulates the process of ordering and inventory management in e-commerce. After reading the previous blogs, I believe this blog will not be any more difficult for you. Some content that is not relevant to the study of this chapter will not be explained too much. Friends who need it can download the source code and check it for themselves. rabbit and spring Integrated Actual Source Code.

Producer Order System

1. Introducing related packages into pom files

rabbit and spring are required to integrate the following two packages

    <dependency>
      <groupId>com.rabbitmq</groupId>
      <artifactId>amqp-client</artifactId>
      <version>5.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.amqp</groupId>
      <artifactId>spring-rabbit</artifactId>
      <version>2.0.0.RELEASE</version>
    </dependency>

Other packages are imported according to project needs; other packages that are interested in viewing can be downloaded to view the source code.

Configuration files

web.xml and spring-mvc.xml are not the focus of the blog, they are no longer posted, and they are interested in downloading source code for viewing. The content of applicationContext.xml is explained below:

1. Namespaces are added to the configuration file:

xmlns:rabbit="http://www.springframework.org/schema/rabbit"
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-2.0.xsd

1. Connection Factory Configuration

    <!-- rabbitMQ To configure -->
    <bean id="rabbitConnectionFactory"
          class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
        <constructor-arg value="127.0.0.1"/>
        <property name="username" value="guest"/>
        <property name="password" value="guest"/>
        <property name="channelCacheSize" value="8"/>
        <property name="port" value="5672"></property>
        <!-- Publishing confirmation must be configured in CachingConnectionFactory upper -->
        <property name="publisherConfirms" value="true"/>
    </bean>

2,<rabbit:admin>

Only after configuring < rabbit: admin > can we produce queue switches and other information according to the configuration file.

<rabbit:admin connection-factory="rabbitConnectionFactory"/>

4. Declaration queue

durable: persistence or not

<rabbit:queue name="depot_queue" durable="true"/>

5. Declarations Exchange

Name: switch name, durable: persistent or not

    <rabbit:direct-exchange name="depot-amount-exchange"
          xmlns="http://www.springframework.org/schema/rabbit" durable="true">
        <rabbit:bindings>
            <rabbit:binding queue="depot_queue" key="amount.depot" ></rabbit:binding>
        </rabbit:bindings>
    </rabbit:direct-exchange>

6. Binding queues and switches

Queue: queue name, key: the bound routing key, which needs to be bound in the switch.

        <rabbit:bindings>
            <rabbit:binding queue="depot_queue" key="amount.depot" ></rabbit:binding>
        </rabbit:bindings>

7. The producer side declares RabbitmqTemplate

    <!-- Establish rabbitTemplate Message Template Class -->
    <bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate">
        <constructor-arg ref="rabbitConnectionFactory"></constructor-arg>
        <!--Message confirmation callback -->
        <property name="confirmCallback" ref="confirmCallback"/>
        <property name="returnCallback" ref="sendReturnCallback"/>
    </bean>

The complete application Context. XML file is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Find the latest schemaLocation Visit http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       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.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd
    http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-2.0.xsd">

     <!-- Configure the scan path -->
     <context:component-scan base-package="com.dongnaoedu">
         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
     </context:component-scan>

    <!-- rabbitMQ To configure -->
    <bean id="rabbitConnectionFactory"
          class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
        <constructor-arg value="127.0.0.1"/>
        <property name="username" value="guest"/>
        <property name="password" value="guest"/>
        <property name="channelCacheSize" value="8"/>
        <property name="port" value="5672"></property>
        <!-- Publishing confirmation must be configured in CachingConnectionFactory upper -->
        <property name="publisherConfirms" value="true"/>
    </bean>
    <rabbit:admin connection-factory="rabbitConnectionFactory"/>

    <rabbit:queue name="depot_queue" durable="true"/>

    <rabbit:direct-exchange name="depot-amount-exchange"
          xmlns="http://www.springframework.org/schema/rabbit" durable="true">
        <rabbit:bindings>
            <rabbit:binding queue="depot_queue" key="amount.depot" ></rabbit:binding>
        </rabbit:bindings>
    </rabbit:direct-exchange>

    <!-- Establish rabbitTemplate Message Template Class -->
    <bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate">
        <constructor-arg ref="rabbitConnectionFactory"></constructor-arg>
        <!--Message confirmation callback -->
        <property name="confirmCallback" ref="confirmCallback"/>
    </bean>
</beans>

3. Other Codes

1,controller

package com.dongnaoedu.controller;

import com.dongnaoedu.service.ProcessOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class OrderController {

    private Logger logger = LoggerFactory.getLogger(OrderController.class);
    private static final String SUCCESS = "suc";
    private static final String FAILUER = "failure";

    @Autowired
    private ProcessOrder processOrder;

    @RequestMapping("/order")
    public String userReg(){
        return "index";
    }

    @RequestMapping("/confirmOrder")
    @ResponseBody
    public String confirmOrder(@RequestParam("goodsId")String goodsId,
                           @RequestParam("amount")int amount){
        try {
            processOrder.processOrder(goodsId,amount);
            return SUCCESS;
        } catch (Exception e) {
            logger.error("Order confirmation exception!",e);
            return FAILUER;
        }
    }
}

2,ProcessOrder

package com.dongnaoedu.service;

import com.dongnaoedu.rpc.DepotService;
import com.dongnaoedu.rpc.RpcProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import sun.security.x509.IPAddressName;

import java.net.InetSocketAddress;

@Service
public class ProcessOrder {
    private Logger logger = LoggerFactory.getLogger(ProcessOrder.class);

    @Autowired
    @Qualifier("mq")
    private IProDepot proDepot;

    public void processOrder(String goodsId,int amount){
        try {
            Thread.sleep(80);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("--------------------["+goodsId+"]Order warehousing completed, ready to change inventory!");
        proDepot.processDepot(goodsId,amount);

    }
}

3,MqMode

Producers can send messages by rabbitTemplate calling send method with parameters of exchange switch, routingKey routing key and Message object.

package com.dongnaoedu.service;

import com.dongnaoedu.vo.GoodTransferVo;
import com.google.gson.Gson;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
@Qualifier("mq")
public class MqMode  implements IProDepot {

    private final static String DEPOT_RK = "amount.depot";
    private final static String DEPOT_EXCHANGE = "depot-amount-exchange";

    @Autowired
    RabbitTemplate rabbitTemplate;

    private static Gson gson = new Gson();

    public void processDepot(String goodsId, int amount) {
        GoodTransferVo goodTransferVo = new GoodTransferVo();
        goodTransferVo.setGoodsId(goodsId);
        goodTransferVo.setChangeAmount(amount);
        goodTransferVo.setInOrOut(false);
        String goods = gson.toJson(goodTransferVo);
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);//Set the message properties for message persistence, and the delivery mode is set to 2.
        rabbitTemplate.send(DEPOT_EXCHANGE, DEPOT_RK,new Message(goods.getBytes(), messageProperties));
    }
}

4,ConfirmCallback

The RabbitTemplate.ConfirmCallback interface must be implemented for message confirmation and callback

package com.dongnaoedu.service.callback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.stereotype.Service;

@Service
public class ConfirmCallback implements RabbitTemplate.ConfirmCallback {
    private Logger logger = LoggerFactory.getLogger(ConfirmCallback.class);

    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            logger.info("Message confirmation is sent to mq Success");
        } else {
            //Dealing with failed messages
            logger.info("Messages are sent to mq fail,Consider repeating:"+cause);
        }
    }
}

Consumer Inventory System

Configuration files

Other configuration files can be downloaded for source viewing.
applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- Find the latest schemaLocation Visit http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       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.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd
    http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-2.0.xsd">

     <!-- Configure the scan path -->
     <context:component-scan base-package="com.dongnaoedu">
         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
     </context:component-scan>

    <!-- rabbitMQ To configure -->
    <bean id="rabbitConnectionFactory"
          class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory">
        <constructor-arg value="127.0.0.1"/>
        <property name="username" value="guest"/>
        <property name="password" value="guest"/>
        <property name="channelCacheSize" value="8"/>
        <property name="port" value="5672"></property>
    </bean>
    <rabbit:admin connection-factory="rabbitConnectionFactory"/>

    <rabbit:queue name="depot_queue" durable="true"/>

    <rabbit:direct-exchange name="depot-amount-exchange"
          xmlns="http://www.springframework.org/schema/rabbit" durable="true">
        <rabbit:bindings>
            <rabbit:binding queue="depot_queue" key="amount.depot" ></rabbit:binding>
        </rabbit:bindings>
    </rabbit:direct-exchange>

    <!-- Manual confirmation of messages -->
    <rabbit:listener-container connection-factory="rabbitConnectionFactory"
                               acknowledge="manual">
        <rabbit:listener queues="depot_queue" ref="processDepot"
                         method="onMessage" />
    </rabbit:listener-container>
</beans>  

II. Other Source Codes

1,ProcessDepot

package com.dongnaoedu.mq;

import com.dongnaoedu.service.DepotManager;
import com.dongnaoedu.vo.GoodTransferVo;
import com.google.gson.Gson;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;

@Service
public class ProcessDepot  implements ChannelAwareMessageListener {

    private static Logger logger = LoggerFactory.getLogger(ProcessDepot.class);

    @Autowired
    private DepotManager depotManager;

    private static Gson gson = new Gson();

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        try {
            String msg = new String(message.getBody());
            logger.info(">>>>>>>>>>>>>>Received message:"+msg);
            GoodTransferVo goodTransferVo = gson.fromJson(msg,GoodTransferVo.class);
            try {
                depotManager.operDepot(goodTransferVo);
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),
                        false);
                logger.info(">>>>>>>>>>>>>>Inventory disposal completed, response Mq service");
            } catch (Exception e) {
                logger.error(e.getMessage());
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);//Delivery Tag Delivery Marker, Does multiple reply in batches, and does requeue requeue re-queue to distribute messages
                logger.info(">>>>>>>>>>>>>>Inventory processing failure, rejection message, request Mq Re dispatch");
                throw e;
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }
}

2,DepotManager

package com.dongnaoedu.service;

import com.dongnaoedu.vo.GoodTransferVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DepotManager {

    @Autowired
    private Depot depot;

    public void operDepot(GoodTransferVo goodTransferVo){
        if(goodTransferVo.isInOrOut()){
            depot.inDepot(goodTransferVo.getGoodsId(),goodTransferVo.getChangeAmount());
        }else{
            depot.outDepot(goodTransferVo.getGoodsId(),goodTransferVo.getChangeAmount());
        }
    }

}

3,Depot

package com.dongnaoedu.service;

import com.dongnaoedu.rpc.DepotService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;

@Service
public class Depot {

    private static Logger logger = LoggerFactory.getLogger(Depot.class);

    private ConcurrentHashMap<String,Integer> goodsData =
            new ConcurrentHashMap<String, Integer>();

    @PostConstruct
    public void initDepot(){
        goodsData.put("001",1000);
        goodsData.put("002",500);
        goodsData.put("003",600);
        goodsData.put("004",700);
    }


    /*Use this method below jdk1.8
    public synchronized void inDepot(String goodsId,int addAmout){
        int amount = goodsData.get(goodsId)+addAmout;
        goodsData.put(goodsId,amount);
    }
    */
    //Increase inventory
    public void inDepot(String goodsId,int addAmout){
        logger.info("+++++++++++++++++Increase commodities:"+goodsId+"Stock,The quantity is:"+addAmout);
        int newValue = goodsData.compute(goodsId, new BiFunction<String, Integer, Integer>() {
            public Integer apply(String s, Integer integer) {
                return integer == null ? addAmout : integer + addAmout;
            }
        });
        logger.info("+++++++++++++++++Commodity:"+goodsId+"Stock,The number becomes:"+newValue);
    }

     /*Use this method below jdk1.8
    public synchronized void outDepot(String goodsId,int reduceAmout){
        int amount = goodsData.get(goodsId)-reduceAmout;
        goodsData.put(goodsId,amount);
    }
    */
    //Reduce stock
    public void outDepot(String goodsId,int reduceAmout){
        logger.info("-------------------Reducing commodities:"+goodsId+"Stock,The quantity is:"+reduceAmout);
        int newValue = goodsData.compute(goodsId, new BiFunction<String, Integer, Integer>() {
            public Integer apply(String s, Integer integer) {
                return integer == null ? 0 : integer - reduceAmout;
            }
        });
        logger.info("-------------------Commodity:"+goodsId+"Stock,The number becomes:"+newValue);
    }

    public int getGoodsAmount(String goodsId){
        return goodsData.get(goodsId);
    }
}

Supplement: The rpc call part of the source code is explained here. Interested friends can study it by themselves. Source Link: rabbit and spring Integrated Actual Source Code.

Posted by .-INSANE-. on Wed, 30 Jan 2019 12:48:15 -0800