源无极

导航

 

一、JMS介绍和使用场景及基础编程模型


    简介:讲解什么是小写队列,JMS的基础知识和使用场景
    1、什么是JMS: Java消息服务(Java Message Service),Java平台中关于面向消息中间件的接口

    2、JMS是一种与厂商无关的 API,用来访问消息收发系统消息,它类似于JDBC(Java Database Connectivity)。这里,JDBC 是可以用来访问许多不同关系数据库的 API

    3、使用场景:

        1)跨平台 

        2)多语言 

        3)多项目

        4)解耦

        5)分布式事务(业务涉及多个表比如:转账)

        6)流量控制(访问量)
        7)最终一致性
        8)RPC调用
            上下游对接,数据源变动->通知下属

4.案例分析

1)网购支付流程:不用消息中间件服务(使用用户流量少的情况)

2)当用户非常多的时候显然我们的支付网关容易崩溃,同时支付网关之后的系统等待时间可能过长,所以需要用到消息服务

分析:支付网关将信息放到消息服务之后,不需要等待积分或是订单系统的执行,提高了系统的并发性和承受的流量(积分订单系统订阅消息)

5、概念    
        JMS提供者:Apache ActiveMQ、RabbitMQ、Kafka、Notify、MetaQ、RocketMQ
        JMS生产者(Message Producer)
        JMS消费者(Message Consumer)
        JMS消息
        JMS队列
        JMS主题

        JMS消息通常有两种类型:点对点(Point-to-Point)、发布/订阅(Publish/Subscribe)

3)消息点对点类型(单个系统)

4)发布/订阅(Publish/Subscribe)

微信支付就是这种模式


   6、编程模型
        MQ中需要用的一些类
        ConnectionFactory :连接工厂,JMS 用它创建连接
        Connection :JMS 客户端到JMS Provider 的连接
        Session: 一个发送或接收消息的线程
        Destination :消息的目的地;消息发送给谁.
        MessageConsumer / MessageProducer: 消息接收者,消费者

 

二、ActiveMQ5.x消息队列基础介绍和安装
    


    简介:介绍ActiveMQ5.x消息队列基础特性和本地快速安装
        特点:
            1)支持来自Java,C,C ++,C#,Ruby,Perl,Python,PHP的各种跨语言客户端和协议
            2)支持许多高级功能,如消息组,虚拟目标,通配符和复合目标
            3) 完全支持JMS 1.1和J2EE 1.4,支持瞬态,持久,事务和XA消息
            4) Spring支持,ActiveMQ可以轻松嵌入到Spring应用程序中,并使用Spring的XML配置机制进行配置
            5) 支持在流行的J2EE服务器(如TomEE,Geronimo,JBoss,GlassFish和WebLogic)中进行测试
            6) 使用JDBC和高性能日志支持非常快速的持久化(重要消息放到mysql或是日志作为备份)
            ...

        1、下载地址:http://activemq.apache.org/activemq-5153-release.html


        2、快速开始:http://activemq.apache.org/getting-started.html
        3、如果我们是32位的机器,就双击win32目录下的activemq.bat,如果是64位机器,则双击win64目录下的activemq.bat
        4、bin目录里面启动 选择对应的系统版本和位数,activeMQ start 启动


        5、启动后访问路径http:// 127.0.0.1:8161/

          127.0.0.1是activeMq安装的服务器,默认端口号8161

  

 

        6、用户名和密码默认都是admin验证这是消息服务的保护措施

登入后的页面:ActiveMQ控制台

1)Home | Queues | Topics | Subscribers | Connections | Network | Scheduled | Send
Support

主页| 队列| 主题| 订阅者| 连接| 网络| 预定| 发送
支持

2)Queues创建

    面板说明:    
        Name:队列名称。
        Number Of Pending Messages:等待消费的消息个数。
        Number Of Consumers:当前连接的消费者数目
        Messages Enqueued:进入队列的消息总个数,包括出队列的和待消费的,这个数量只增不减。
        Messages Dequeued:已经消费的消息数量。

3)向消息队列发送消息

结果


        7、官方案例集合
            https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples
    


三、SpringBoot2.x整合ActiveMQ实战之点对点消息(p2p)
   消息 消费者和消息生产者可以在一个工程也可以在不同的工程


    简介:SpringBoot2.x整合ActiveMQ实战之点对点消息

    1、官网地址:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-activemq

    2、加入依赖
        <!-- 整合消息队列ActiveMQ -->
     

   
 1        <dependency>  
 2             <groupId>org.springframework.boot</groupId>  
 3             <artifactId>spring-boot-starter-activemq</artifactId>  
 4         </dependency>  
 5         
 6         <!-- 如果配置线程池则加入 -->
 7         <dependency>  
 8             <groupId>org.apache.activemq</groupId>  
 9             <artifactId>activemq-pool</artifactId>  
10         </dependency>

 

     3、application.properties配置文件配置
     

 1 #整合jms测试,安装在别的机器,防火墙和端口号记得开放
 2 spring.activemq.broker-url=tcp://127.0.0.1:61616
 3 #集群配置,61616:开启对外连接的默认端口号
 4 #spring.activemq.broker-url=failover:(tcp://localhost:61616,tcp://localhost:61617)
 5 
 6 spring.activemq.user=admin
 7 spring.activemq.password=admin
 8 #下列配置要增加依赖:消息队列连接池 max-connections,50,100,500根据需要写
 9 spring.activemq.pool.enabled=true
10 spring.activemq.pool.max-connections=100

 

 

      4、springboot启动类 @EnableJms,开启支持jms

1)service接口

 1 package com.itcast.demo.service;
 2 
 3 import javax.jms.Destination;
 4 
 5 /**
 6  * 
 7 * <p>Title: ProducerService</p>  
 8 * <p>Description: </p>  
 9 * @author shenlan  
10 * @date 2018年11月4日
11  */
12 
13 public interface ProducerService {
14     /**
15      * 指定消息队列还有消息
16      * @param destination
17      * @param message
18      */
19     public void sendMessage(Destination destination,final String message );
20     /**
21      * 
22      * 使用默认消息队列发送消息
23      * @param message
24      */
25     public void sendMessage(final String message );
26 }

 

    2)实现

 1 package com.itcast.demo.service.impl;
 2 
 3 import javax.jms.Destination;
 4 import javax.jms.Queue;
 5 
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.jms.core.JmsMessagingTemplate;
 8 import org.springframework.stereotype.Service;
 9 
10 import com.itcast.demo.service.ProducerService;
11 
12 
13 @Service
14 public class ProducerServiceImpl implements ProducerService{
15      //用来发送消息到broker的对象
16     @Autowired
17    private JmsMessagingTemplate jmsTemplate ;
18     
19     @Autowired
20     private Queue queue;//程序入口有了
21     //发送消息,destination是发送到的队列,message是待发送的消息
22     @Override
23     public void sendMessage(Destination destination, String message) {
24         jmsTemplate.convertAndSend(destination,message);
25         
26     }
27 
28     //发送消息,destination是发送到的队列,message是待发送的消息
29     @Override
30     public void sendMessage(String message) {
31         jmsTemplate.convertAndSend(this.queue,message);
32     }
33 
34 }

 

 

3)controller

 1 package com.itcast.demo.controller;
 2 
 3 import javax.jms.Destination;
 4 
 5 
 6 import org.apache.activemq.command.ActiveMQQueue;
 7 import org.springframework.beans.factory.annotation.Autowired;
 8 import org.springframework.web.bind.annotation.GetMapping;
 9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RestController;
11 
12 import com.itcast.demo.domain.JsonData;
13 import com.itcast.demo.service.ProducerService;
14 
15 /**
16  * 功能描述:模拟微信支付回调
17  *
18  *
19  *@作者 llj  小D
20  */
21 @RestController
22 @RequestMapping("/api/v1")
23 public class OrderController {
24     
25     @Autowired
26     private ProducerService producerService;
27     /**
28      * 功能描述:微信支付回调接口
29      * @param msg 支付信息
30      * @return
31      */
32     @GetMapping("order")
33     public Object order(String msg){//实际开发msg是html需要document解析
34         
35         Destination destination = new ActiveMQQueue("order.queue");
36         
37         producerService.sendMessage(destination, msg);
38     
39        return JsonData.buildSuccess();
40     }
41     
42     
43     
44     @GetMapping("common")
45     public Object common(String msg){
46         producerService.sendMessage(msg);    
47        return JsonData.buildSuccess();
48     }
49     
50     
51     
52     
53 }

 

 4)控制台创建队列

5)启动工程访问

6)刷新

7)再发送

消息变成两条

     5、消费者:实时监听对应的队列()
          @JmsListener(destination = "order.queue")
     1)     建立一个jms包下面建立OrderConsumer 类

 1 package com.itcast.demo.jms;
 2 
 3 import org.springframework.jms.annotation.JmsListener;
 4 import org.springframework.stereotype.Component;
 5 @Component  //spring可以扫描
 6 public class OrderConsumer {
 7     /**
 8      * 
 9      * @JmsListener监听order.queue队列有没有消息进来
10      * @param text
11      */
12     @JmsListener(destination="order.queue")
13     public void receiveQueue(String text){
14         System.out.println("OrderConsumer收到的报文为:"+text);
15     }
16 }

 

2)启动工程之前写的报文都收到了

3)刷新控制台

4)再添加消息

6.测一下默认的队列comment.queue

1)和OrderConsumer 类一样

 1 package com.itcast.demo.jms;
 2 
 3 import org.springframework.jms.annotation.JmsListener;
 4 import org.springframework.stereotype.Component;
 5 
 6 @Component
 7 public class CommonConsumer {
 8     
 9     @JmsListener(destination="comment.queue")
10     public void receiveQueue(String text){
11         System.out.println("CommonConsumer收到的报文为:"+text);
12     }
13     
14 }

 

 

2)

3)

 

四、SpringBoot整合ActiveMQ实战之发布订阅模式(pub/sub)


    简介:SpringBoot整合ActiveMQ实战之发布订阅模式(pub/sub),及同时支持点对点和发布订阅模型

        1、需要加入配置文件,支持发布订阅模型,默认只支持点对点
            #default point to point
            spring.jms.pub-sub-domain=true

    注意点:
        
        1、默认消费者并不会消费订阅发布类型的消息,这是由于springboot默认采用的是p2p模式进行消息的监听
           1) 修改配置:spring.jms.pub-sub-domain=true
         2)在程序入口处加入topic对象,好处是启动程序new 一次可以多次使用

 1 package com.itcast.demo;
 2 
 3 import javax.jms.Queue;
 4 import javax.jms.Topic;
 5 import javax.servlet.MultipartConfigElement;
 6 
 7 import org.apache.activemq.command.ActiveMQQueue;
 8 import org.apache.activemq.command.ActiveMQTopic;
 9 import org.springframework.boot.SpringApplication;
10 import org.springframework.boot.autoconfigure.SpringBootApplication;
11 import org.springframework.boot.web.servlet.MultipartConfigFactory;
12 import org.springframework.context.annotation.Bean;
13 import org.springframework.jms.annotation.EnableJms;
14 import org.springframework.scheduling.annotation.EnableAsync;
15 import org.springframework.scheduling.annotation.EnableScheduling;
16 import org.springframework.web.bind.annotation.RequestMapping;
17 import org.springframework.web.bind.annotation.RestController;
18 
19 @SpringBootApplication
20 @EnableJms
21 public class Application {
22     //交个spring进行管理,方便后续进行注入
23     @Bean
24     public Queue queue(){
25         return new ActiveMQQueue("comment.queue");
26     }
27    //主题对象交给spring管理
28     @Bean
29        public Topic topic(){
30            return new ActiveMQTopic("video.topic");
31        }
32     public static void main(String[] args) {
33         SpringApplication.run(Application.class, args);
34     }
35     
36 }

 

 

    3)ProducerService接口添加如下代码

1     /**
2      * 
3      * 消息发布者
4      * @param message
5      */
6     public void publish(String msg) ;

 

 

  4)实现类ProducerServiceImpl

 1 //=======发布订阅相关代码=========
 2     
 3     @Autowired
 4     private Topic topic;
 5     
 6      @Override
 7     public void publish(String msg) {
 8         this.jmsTemplate.convertAndSend(this.topic, msg);
 9         
10     }

 

 

5)controller

1   @GetMapping("topic")
2     public Object topic(String msg){
3         producerService.publish(msg);
4        return JsonData.buildSuccess();
5     }
6     

 

6)启动程序,访问

7)

8)TopicSub  :模拟一个订阅者

 1 package com.itcast.demo.jms;
 2 
 3 import org.springframework.jms.annotation.JmsListener;
 4 import org.springframework.stereotype.Component;
 5 @Component
 6 public class OrderConsumer {
 7     /**
 8      * 
 9      * @JmsListener监听order.queue队列有没有消息进来
10      * @param text
11      */
12     @JmsListener(destination="order.queue")
13     public void receiveQueue(String text){
14         System.out.println("OrderConsumer收到的报文为:"+text);
15     }
16 }

 

9)启动访问



控制台

10)模拟三个订阅者

 1 package com.itcast.demo.jms;
 2 
 3 import org.springframework.jms.annotation.JmsListener;
 4 import org.springframework.stereotype.Component;
 5 
 6 @Component
 7 public class TopicSub {
 8     //模拟出三个订阅者
 9     
10     @JmsListener(destination="video.topic")
11     public void receive1(String text){
12         System.out.println("video.topic 消费者:receive1="+text);
13     }
14     
15     
16     @JmsListener(destination="video.topic")
17     public void receive2(String text){
18         System.out.println("video.topic 消费者:receive2="+text);
19     }
20     @JmsListener(destination="video.topic")
21     public void receive3(String text){
22         System.out.println("video topic 消费者:receive3="+text);
23     }
24     
25     
26 }

 

 11)访问

12)此时存在一个问题:点对点模式没有生效

我们测点对点时,并没有消费者

 

13)@JmsListener如果不指定独立的containerFactory的话是只能消费queue消息
       也就是只支持一种模式

 

            //需要给topic定义独立的JmsListenerContainer
            

          a)  在配置文件里面,注释掉 #spring.jms.pub-sub-domain=true

         b)在程序入口加入

1 @Bean
2     public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ConnectionFactory   activeMQConnectionFactory) {
3         DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
4         bean.setPubSubDomain(true);//支持订阅模式
5         bean.setConnectionFactory(activeMQConnectionFactory);
6         return bean;
7     }

 

 

c)   修改订阅者container:containerFactory="jmsListenerContainerTopic"

 1 package com.itcast.demo.jms;
 2 
 3 import org.springframework.jms.annotation.JmsListener;
 4 import org.springframework.stereotype.Component;
 5 
 6 @Component
 7 public class TopicSub {
 8     //模拟出三个订阅者
 9     
10     @JmsListener(destination="video.topic",containerFactory="jmsListenerContainerTopic")
11     public void receive1(String text){
12         System.out.println("video.topic 消费者:receive1="+text);
13     }
14     
15     
16     @JmsListener(destination="video.topic",containerFactory="jmsListenerContainerTopic")
17     public void receive2(String text){
18         System.out.println("video.topic 消费者:receive2="+text);
19     }
20     @JmsListener(destination="video.topic",containerFactory="jmsListenerContainerTopic")
21     public void receive3(String text){
22         System.out.println("video topic 消费者:receive3="+text);
23     }
24     
25     
26 }

 

14)order点对点模式,

15)发布订阅模式

 

posted on 2018-11-29 22:28  源无极  阅读(225)  评论(0编辑  收藏  举报