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.