java 编程技术异步通信_java异步消息通知机制(1)

注册服务

ln -s /opt/activemq/bin/activemq /etc/init.d/activemqchkconfig --add activemq

复制代码

启动服务

service activemq start

关闭服务

service activemq stop

通过 netstat 查看端口

activemq 两个重要的端口,一个是提供消息队列的默认端口:61616

另一个是控制台端口 8161

通过控制台测试

启动消费端

进入网页控制台

账号/密码默认: admin/admin

点击 Queues

观察客户端

在 Java 中使用消息队列

3.1 在 gmall-service-util 中导入依赖坐标

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-activemq</artifactId><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.apache.activemq</groupId><artifactId>activemq-pool</artifactId><version>5.15.2</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency>

复制代码

3.2 producer 端

public static void main(String[] args) {ConnectionFactory connect = new ActiveMQConnectionFactory("tcp://192.168.67.163:61616");try {Connection connection = connect.createConnection();connection.start();//第一个值表示是否使用事务,如果选择true,第二个值相当于选择0Session session = connection.createSession(true, Session.SESSION_TRANSACTED);Queue testqueue = session.createQueue("TEST1");MessageProducer producer = session.createProducer(testqueue);TextMessage textMessage=new ActiveMQTextMessage();textMessage.setText("今天天气真好!");producer.setDeliveryMode(DeliveryMode.PERSISTENT);producer.send(textMessage);session.commit();connection.close();} catch (JMSException e) {e.printStackTrace();}}

复制代码

3.3 consumer

public static void main(String[] args) {ConnectionFactory connect = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,ActiveMQConnection.DEFAULT_PASSWORD,"tcp://192.168.67.163:61616");try {Connection connection = connect.createConnection();connection.start();//第一个值表示是否使用事务,如果选择true,第二个值相当于选择0Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);Destination testqueue = session.createQueue("TEST1");MessageConsumer consumer = session.createConsumer(testqueue);consumer.setMessageListener(new MessageListener() {@Overridepublic void onMessage(Message message) {if(message instanceof TextMessage){try {String text = ((TextMessage) message).getText();System.out.println(text);//session.rollback();} catch (JMSException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}});}catch (Exception e){e.printStackTrace();}}

复制代码

3.4 关于事务控制

3.5 持久化与非持久化

通过 producer.setDeliveryMode(DeliveryMode.PERSISTENT) 进行设置

持久化的好处就是当 activemq 宕机的话,消息队列中的消息不会丢失。非持久化会丢失。但是会消耗一定的性能。

四 与 springboot 整合

1 配置类 ActiveMQConfig

@Configurationpublic class ActiveMQConfig {@Value("${spring.activemq.broker-url:disabled}")String brokerURL ;@Value("${activemq.listener.enable:disabled}")String listenerEnable;@Beanpublic ActiveMQUtil getActiveMQUtil() throws JMSException {if(brokerURL.equals("disabled")){return null;}ActiveMQUtil activeMQUtil=new ActiveMQUtil();activeMQUtil.init(brokerURL);return activeMQUtil;}//定义一个消息监听器连接工厂,这里定义的是点对点模式的监听器连接工厂@Bean(name = "jmsQueueListener")public DefaultJmsListenerContainerFactory jmsQueueListenerContainerFactory(ActiveMQConnectionFactory activeMQConnectionFactory ) {DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();if(!listenerEnable.equals("true")){return null;}factory.setConnectionFactory(activeMQConnectionFactory);//设置并发数factory.setConcurrency("5");//重连间隔时间 factory.setRecoveryInterval(5000L);factory.setSessionTransacted(false);factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);return factory;}@Beanpublic ActiveMQConnectionFactory activeMQConnectionFactory ( ){ActiveMQConnectionFactory activeMQConnectionFactory =new ActiveMQConnectionFactory( brokerURL);return activeMQConnectionFactory;}}

复制代码

2 工具类 ActiveMQUtil
public class ActiveMQUtil {PooledConnectionFactory pooledConnectionFactory=null;public ConnectionFactory init(String brokerUrl) {ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUrl);//加入连接池pooledConnectionFactory=new PooledConnectionFactory(factory);//出现异常时重新连接pooledConnectionFactory.setReconnectOnException(true);//pooledConnectionFactory.setMaxConnections(5);pooledConnectionFactory.setExpiryTimeout(10000);return pooledConnectionFactory;}public ConnectionFactory getConnectionFactory(){return pooledConnectionFactory;}}

复制代码

五 在支付业务模块中应用

1 支付成功通知

支付模块利用消息队列通知订单系统,支付成功

在支付模块中配置 application.properties

spring.activemq.broker-url=tcp://mq.server.com:61616

复制代码

在 PaymentServiceImpl 中增加发送方法:

public void sendPaymentResult(String orderId,String result){ConnectionFactory connectionFactory = activeMQUtil.getConnectionFactory();Connection connection=null;try {connection = connectionFactory.createConnection();connection.start();Session session = connection.createSession(true, Session.SESSION_TRANSACTED);Queue paymentResultQueue = session.createQueue("PAYMENT_RESULT_QUEUE");MapMessage mapMessage=new ActiveMQMapMessage();mapMessage.setString("orderId",orderId);mapMessage.setString("result",result);MessageProducer producer = session.createProducer(paymentResultQueue);producer.send(mapMessage);session.commit();

复制代码

producer.close();session.close();connection.close();} catch (JMSException e) {e.printStackTrace();}}

复制代码

在 PaymentController 中增加一个方法用来测试

@RequestMapping("sendResult")@ResponseBodypublic String sendPaymentResult(@RequestParam("orderId") String orderId){paymentService.sendPaymentResult(orderId,"success" );return "has been sent";}

复制代码

在浏览器中访问:

查看队列内容:有一个在队列中没有被消费的消息。

2 订单模块消费消息

application.properties

spring.activemq.broker-url=tcp://mq.server.com:61616activemq.listener.enable=true

复制代码

订单消息消息后要更新订单状态,先准备好订单状态更新的方法

public void updateProcessStatus(String orderId , ProcessStatus processStatus, Map<String,String>... paramMaps) {OrderInfo orderInfo = new OrderInfo();orderInfo.setId(orderId);orderInfo.setOrderStatus(processStatus.getOrderStatus());orderInfo.setProcessStatus(processStatus);//动态增加需要补充更新的属性if (paramMaps != null && paramMaps.length > 0) {Map<String, String> paramMap = paramMaps[0];for (Map.Entry<String, String> entry : paramMap.entrySet()) {String properties = entry.getKey();String value = entry.getValue();try {BeanUtils.setProperty(orderInfo, properties, value);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}orderInfoMapper.updateByPrimaryKeySelective(orderInfo);}

复制代码

消息队列的消费端

@JmsListener(destination = "PAYMENT_RESULT_QUEUE",containerFactory = "jmsQueueListener")public void consumePaymentResult(MapMessage mapMessage) throws JMSException {String orderId = mapMessage.getString("orderId");String result = mapMessage.getString("result");if(!"success".equals(result)){orderService.updateProcessStatus( orderId , ProcessStatus.PAY_FAIL);}else{orderService.updateProcessStatus( orderId , ProcessStatus.PAID);} orderService.sendOrderResult(orderId);}

复制代码

3 订单模块发送减库存通知

订单模块除了接收到请求改变单据状态,还要发送库存系统

查看看《库存管理系统接口手册》中【减库存的消息队列消费端接口】中的描述,组织相应的消息数据进行传递。

@Transactionalpublic void sendOrderResult(String orderId){OrderInfo orderInfo = getOrderInfo(orderId);Map<String, Object> messageMap = initWareOrderMessage(orderInfo);String wareOrderJson= JSON.toJSONString(messageMap);Session session = null;try {Connection conn = activeMQUtil.getConnection();session = conn.createSession(true, Session.SESSION_TRANSACTED);Queue queue = session.createQueue("ORDER_RESULT_QUEUE");MessageProducer producer = session.createProducer(queue);TextMessage message =new ActiveMQTextMessage();message.setText(wareOrderJson);producer.send(message);updateProcessStatus(orderInfo.getId(), ProcessStatus.NOTIFIED_WARE);session.commit();producer.close();conn.close();} catch (JMSException e) {e.printStackTrace();}}

复制代码

针对接口手册中需要的消息进行组织

public Map<String,Object> initWareOrderMessage( OrderInfo orderInfo ) {//准备发送到仓库系统的订单String wareId = orderInfo.getWareId();HashMap<String, Object> hashMap = new HashMap<>();hashMap.put("orderId", orderInfo.getId());hashMap.put("consignee", orderInfo.getConsignee());hashMap.put("consigneeTel", orderInfo.getConsigneeTel());hashMap.put("orderComment", orderInfo.getOrderComment());hashMap.put("orderBody", orderInfo.getOrderSubject());hashMap.put("deliveryAddress", orderInfo.getDeliveryAddress());hashMap.put("paymentWay", "2");//1 货到付款 2 在线支付hashMap.put("wareId",wareId);List<HashMap<String, String>> details = new ArrayList<>();List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();for (OrderDetail orderDetail : orderDetailList) {HashMap<String, String> detailMap = new HashMap<>();detailMap.put("skuId", orderDetail.getSkuId());detailMap.put("skuNum", "" + orderDetail.getSkuNum());detailMap.put("skuName", orderDetail.getSkuName());details.add(detailMap);}hashMap.put("details", details);return hashMap;}

复制代码

4 消费减库存结果

给仓库系统发送减库存消息后,还要接受减库存成功或者失败的消息。

同样根据《库存管理系统接口手册》中【商品减库结果消息】的说明完成。消费该消息的消息队列监听程序。

接受到消息后主要做的工作就是更新订单状态。

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

-xsCEEoHD-1714154383445)]
[外链图片转存中…(img-bzSx5YSI-1714154383445)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
学习Java并发编程是一项需要投入大量时间和精力的任务,但它在现代软件开发中是不可或缺的。通过深入学习线程、同步和异步、互斥和死锁、线程安全性、并发编程模型以及Java并发包等内容,您可以成为一名更加优秀的编程专家。 对于初学者来说,Java并发编程可能会显得晦涩难懂,并且涉及了许多新技术。在学习这一领域之前,建议掌握好相关的理论知识,并打好基础。只有在掌握了基础知识后,才能更好地理解和应用更高层次的概念。 在进行Java并发编程的训练时,以下是一些建议: 1. 了解并掌握Java中的线程机制和线程生命周期。 2. 学习如何使用同步和异步机制来处理并发编程中的数据共享和通信问题。 3. 理解并学习如何使用锁、互斥和死锁的概念以及如何避免它们。 4. 熟悉线程安全性的概念和相关的技术,如volatile关键字和Atomic类。 5. 学习并理解Java提供的并发编程模型,如线程池和Fork/Join框架。 6. 了解并掌握Java并发包中提供的各种类和工具,如Semaphore、CountDownLatch和CyclicBarrier等。 通过不断学习和练习,并发编程的技能会得到提升。建议您多实践编写并发程序,通过解决实际问题来加深对并发编程的理解。祝您在学习Java并发编程的过程中取得成功!<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* *2* [如何学习Java并发编程](https://blog.csdn.net/weixin_42080277/article/details/129785094)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值