zoukankan      html  css  js  c++  java
  • spring in action day-06 JMS -ActiveMQ Artemi

    JMS -ActiveMQ Artemi

    JMS:它是一个规范,类似于jdbctemplate

    Spring提供了jmstemplate来发送和接收消息。

     

    搭建JMS环境

    1.引入依赖

    我们要使用的消息中间件代理是ActiveMQ Artemi,他是ActiveMQ的进阶版

    这里我们要引入的依赖是ActiveMQ Artemis的依赖

    <dependency>
    
    <groupId>org.springframework.boot</groupId>
    
    <artifactId>spring-boot-starter-artemis</artifactId>
    
    </dependency>

    2.配置属性

    spring:
    
      artemis:
    
        host: 消息中间件(ActiveMQ Artemi)所在主机地址
    
    port: 61617
    
    user: admin
    
    password: 123456

     

    备注说明:这个配置,如果是在本地开发运行,这个配置不需要

    3.安装ActiveMQ Artemi

    http://activemq.apache.org/artemis/download.html

     

    解压到
    D:DevToolsapache-artemis-2.6.3-bin

    执行 cmd

    cd /d D:DevToolsapache-artemis-2.6.3-binapache-artemis-2.6.3in

    artemis create D:DevToolsapache-artemis-2.6.3-binmyartemis

    //需要设置一个账号

    Please provide the default username:

    admin

    //需要为这个账号密码设置

    Please provide the default password:

    admin

    //需要设置是否允许匿名登录
    Allow anonymous access?, valid values are Y,N,True,False

    Y

    继续 执行 cmd

    cd /d D:DevToolsapache-artemis-2.6.3-binmyartemisin

    启动实例

    artemis run

     

    PS: 卸载系统服务

    sc delete 服务名

    打开主页

    http://127.0.0.1:8161/

    http://localhost:8161/

     

    8161是它的默认端口

    4.使用JMS发送消息

    4.1 我们在之前引入的ActiveMQ Artemis的依赖,springboot会为我们创建一个JMSTemplate对象,我们只需要注入就可以使用

    @Autowired

    private JmsTemplate jms;

    4.2 JMSTemplate发送消息的方法可以分为三类,每一类又有三个重载方法

    下面三个方法,传输的是Message对象,需要使用转换器把数据对象转换成Message

    send(Message me) //传输Message对象,采用默认地址
    
    Send(Destination dest,Message me) //传输Message对象,采用Destination 的地址
    
    Send(String dest,Message me)//传输Message对象,采用String地址

    下面三个方法,与上面相比,直接传输数据对象而不是message,少了吧对象转换成message的步骤。自动完成转换,转换器使用的是默认的转换器,如果要使用其他转换器,也可以配置

    convertAndSend(Object o)
    
    convertAndSend(Destination dest,Object o)
    
    convertAndSend(String dest,Object o)

    //下面三个方法,与上面相比,多传输了一个对象MessagePostProsser,在这里面可以传入一些数据对象无法传输的信息

    convertAndSend(Object o,MessagePostProsser p)
    
    convertAndSend(Destination dest,Object o,MessagePostProsser p)
    
    convertAndSend(String dest,Object o,MessagePostProsser p)

    关于转换器

    Spring提供了转换器,当然,我们也可以自定义转换器,不过spring提供的已经够用了

    默认使用的是SimpleMessageConverter

    如果我们想要使用别的,比如MappingJackson2MessageConverter 只需要

    package tacos.config;
    
     
    
    import javax.jms.Destination;
    
     
    
    import org.apache.activemq.artemis.jms.client.ActiveMQQueue;
    
    import org.springframework.context.annotation.Bean;
    
    import org.springframework.context.annotation.Configuration;
    
    import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
    
     
    @Configuration
    
    public class JmsConfig {
    
    @Bean
    public MappingJackson2MessageConverter getMessageConverter(){
    
    MappingJackson2MessageConverter m = new MappingJackson2MessageConverter();
    
    //下面是为了让接受者知道是什么类型  在接收端,也要做相应的配置
    
    m.setTypeIdPropertyName("_typeId");
    
    Map<String,Class<?>> ma = new HashMap<>();
    
    ma.put("orga", Organization.class);
    
    m.setTypeIdMappings(ma);
    return m;
      }
    }

    4.3第一类send方法

    1)第一种:一个参数MessageCreator-生成消息

    @RequestMapping(value="/jms0")
    
    public void test0(){
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.send(new MessageCreator() {
    
    第一种使用lamada表达式简写
    
     
    
    @Override
    
    public Message createMessage(Session arg0) throws JMSException {
    
    arg0.createObjectMessage(o);
    
    return null;
    
    }
    
    }); //1个参数   MessageCreator 这个参数用来构建message
    
    System.out.println("发送成功");
    } 

    2) 第二种://2个参数  1.指定目的地及其他信息 2. MessageCreator 这个参数用来构建message

     

    package tacos.config;
    
     
    
    import javax.jms.Destination;
    
     
    
    import org.apache.activemq.artemis.jms.client.ActiveMQQueue;
    
    import org.springframework.context.annotation.Bean;
    
    import org.springframework.context.annotation.Configuration;
    
     
    
    @Configuration
    
    public class JmsConfig {
    
     
    
    @Bean
    
    public Destination getDestination(){
    
    return new ActiveMQQueue("tacocloud.order.queue");
    
    }
    
    }
    
    
    @Autowired
    
    private Destination dist;
    
    @RequestMapping(value="/jms2")
    
    public void test2(){
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.send(dist,session -> session.createObjectMessage(o));//2个参数  1.Destination 指定目的地(还可以指定一些其他信息,不过一般不用) 2. MessageCreator 这个参数用来构建message
    
    System.out.println("发送成功");
    }

    3)第三种://2个参数  1.指定目的地 2. MessageCreator 这个参数用来构建message

        @RequestMapping(value="/jms3")
    
    public void test3(){
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.send("tacocloud.order.mytest",session -> session.createObjectMessage(o));//2个参数  1.指定目的地 2. MessageCreator 这个参数用来构建message
    
    System.out.println("发送成功");
    
    }

    4.4第二类方法convertAndSend

    1) 第一种:一个参数,要发送的对象,不需要构建MessageCreator来转换对象,它会自动转换,更为简单

    @RequestMapping(value="/jms4")
    
    public void test4(){
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.convertAndSend(o);//1个参数  要发送的对象
    
    System.out.println("发送成功");
    
    }

    2) 第二种:2个参数。1:目的地及其他信息,2:要发送的对象,不需要构建MessageCreator来转换对象,它会自动转换,更为简单

     

    @RequestMapping(value="/jms5")
    
    public void test5(){
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.convertAndSend(dist,o);//2个参数  1.Destination 指定目的地(还可以指定一些其他信息,不过一般不用) 2.要发送的对象
    
    System.out.println("发送成功");
    
     
    
    }

    3) 第三种2个参数 1:目的地,2:要发送的对象,不需要构建MessageCreator来转换对象,它会自动转换,更为简单

     

    @RequestMapping(value="/jms6")
    
    public void test6(){
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.convertAndSend("tacocloud.order.mytest2",o);//1个参数  要发送的对象
    
    System.out.println("发送成功");
    
    }

    4.5第三类convertAndSend

    1)第一种,两个参数 1:要传输的对象 2.MessagePostProcessor对象,它可以携带除了要参数的对象以外的信息。比如我传一个USER对象,我还想传本次传输的时间,但是User对象里面没有这个属性,那么就可以在MessagePostProcessor里面传过去

    @RequestMapping(value="/jms7")
    
    public void test7(){ //发送消息本身 和 其他信息
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.convertAndSend(o,new MessagePostProcessor() {
    
    @Override
    
    public Message postProcessMessage(Message arg0) throws JMSException {
    
    arg0.setStringProperty("source", "mytest");
    
    return arg0;
    
    }
    
    });//1个参数  要发送的对象
    
    System.out.println("发送成功");
    
     
    
    }
    
     
    
    使用lamada表达式简写
    
    @RequestMapping(value="/jms8")
    
    public void test8(){ //更简便的写法
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.convertAndSend(o,this::getMessage);//1个参数  要发送的对象
    
    System.out.println("发送成功");
    
     
    
    }
    
    public  Message getMessage(Message me) throws JMSException{
    
     me.setStringProperty("source", "mytest");
    
    return me;
    
    }

    2)第二种

    三个参数 1:目的地及其他信息 2.要参数的对象 3.MessagePostProcessor对象

     

        @RequestMapping(value="/jms9")
    
    public void test9(){ //更简便的写法
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.convertAndSend(dist,o,this::getMessage);//1个参数  要发送的对象
    
    System.out.println("发送成功");
    
     
    
    }

    3)第三种

    三个参数 1:目的地 2.要参数的对象 3.MessagePostProcessor对象

    @RequestMapping(value="/jms10")
    
    public void test10(){ //更简便的写法
    
    Organization o = new Organization();
    
    o.setOrgname("jms测试");
    
    jms.convertAndSend("tacocloud.order.mytest2",o,this::getMessage);//1个参数  要发送的对象
    
    System.out.println("发送成功");
    
     
    
    }

    三类方法做一个小结

    三类方法

    第一类:最为基础,需要使用MessageCreator 来构建message

    第二类:第一类的升级,更为渐变,不需要MessageCreator 来转换,直接传入要传输的对象即可

    底三类:第二类的升级,除了可以参数对象,还可以参数MessagePostProcessor对象来传输其它的任何信息

    3类方法都有3个重载方法

    1. 不带目的地参数
    2. Destination 参数,里面可以包含目的地和其它的一些信息
    3. String参数,也就是目的地

    5.接收JMS消息(拉取模式)

    发送消息的条件

    1. 配置默认目的地 tacocloud.order.mytest3
    spring:  
    
      jms:
    
        template:
    
          default-destination: tacocloud.order.mytest3

      2.使用Destination

    @Bean
    
    public Destination getDestination(){
    
    return new ActiveMQQueue("tacocloud.order.jms2");
    
    }

      3.转换器 MappingJackson2MessageConverter- 和发送消息的转换器对应-如果是默认的转换器,不需要配置

        @Bean
    
    public MappingJackson2MessageConverter getMessageConverter(){
    
    MappingJackson2MessageConverter m = new MappingJackson2MessageConverter();
    
    //下面是为了让接受者知道是什么类型  在接收端,也要做相应的配置
    
    m.setTypeIdPropertyName("_typeId");
    
    Map<String,Class<?>> ma = new HashMap<>();
    
    ma.put("orga", Organization.class);
    
    m.setTypeIdMappings(ma); 
    
    return m;
    
    }
    
    

    接收消息有两个方法receivereceiveAndConvert前者返回message对象,后者返回数据对象。他们也都有3个重载方法。和发送消息一一对应。不论发送消息用的是哪个方法,这两个接收方法都可以接收。注意:目的地要对应,转换器也要对应。

    由于发送和接受在一个项目写的,发送消息转换器已配置了,接收这里转换器就不用配置了

    1)

    @RequestMapping(value="/receivejms1")
    
    public void receivejms1() throws MessageConversionException, JMSException{
    
     
    
    //接收消息,没有参数,接收的是默认地址  接收到的是messsage对象,要获取数据对象,需要使用转换器,这个转换器需要和发送的转换器一致
    
    Message receive = jms.receive();
    
    Organization fromMessage = (Organization) con.fromMessage(receive);
    
    System.out.println(fromMessage.toString());
    
    Destination jmsDestination = receive.getJMSDestination();
    
    System.out.println(jmsDestination.toString());
    
    }

    2)

        @RequestMapping(value="/receivejms2")
    
    public void receivejms2() throws MessageConversionException, JMSException{
    
    //接收消息,多了个参数Destination,接收的是Destination里面的地址  接收到的是messsage对象,要获取数据对象,需要使用转换器,这个转换器需要和发送的转换器一致
    
    //receive 方法
    
    Message receive = jms.receive(dist);
    
    Organization fromMessage = (Organization) con.fromMessage(receive);
    
    System.out.println(fromMessage.toString());
    
    Destination jmsDestination = receive.getJMSDestination();
    
    System.out.println(jmsDestination.toString());
    
    String source = receive.getStringProperty("source");
    
    System.out.println(source);
    
    }

    3)

        @RequestMapping(value="/receivejms3")
    
    public void receivejms3() throws MessageConversionException, JMSException{
    
     
    
    //接收消息,多了个参数地址,接收到的是messsage对象,要获取数据对象,需要使用转换器,这个转换器需要和发送的转换器一致
    
    Message receive = jms.receive("tacocloud.order.jms2");
    
    Organization fromMessage = (Organization) con.fromMessage(receive);
    
    System.out.println(fromMessage.toString());
    
    Destination jmsDestination = receive.getJMSDestination();
    
    System.out.println(jmsDestination.toString());
    
    }

    4)

        @RequestMapping(value="/receivejms4")
    
    public void receivejms4() throws MessageConversionException, JMSException{
    
     
    
    // receiveAndConvert 接收消息 ,没有参数,使用默认地址,接收到的是数据对象,不需要手动转换,自动就转换了
    
    Organization receiveAndConvert = (Organization) jms.receiveAndConvert();
    
     
    
    System.out.println(receiveAndConvert.toString());
    
    }

    5)

    @RequestMapping(value="/receivejms5")
    public void receivejms5() throws MessageConversionException, JMSException{
    // receiveAndConvert 接收消息 ,一个参数Destination,使用Destination地址,接收到的是数据对象,不需要手动转换,自动就转换了
    Organization receiveAndConvert = (Organization) jms.receiveAndConvert(dist);
    System.out.println(receiveAndConvert.toString());
    }

    6)

    @RequestMapping(value="/receivejms6")
    public void receivejms6() throws MessageConversionException, JMSException{
    
    // receiveAndConvert 接收消息 ,一个参数地址,接收到的是数据对象,不需要手动转换,自动就转换了
    
    Organization receiveAndConvert = (Organization) jms.receiveAndConvert("tacocloud.order.jms2");
    
    System.out.println(receiveAndConvert.toString());
    
    }

    小结:receive方法和receiveAndConvert方法,前者接收到的是message对象,包含了数据对象以及其他的一些消息,后者直接接收的是数据对象。两种都有3个重载方法。分别使用默认地址,Destination指定地址,String地址。备注说明(发送消息第三类方法convertAndSend的参数MessagePostProcessor需要使用receive方法获取message对象,在调用getStringProperty方法获取里面的数据。看上面的第二个接收消息方法)

     

    1. 接收JMS消息(推送模式)
    package tacos;
    
     
    
    import javax.jms.JMSException;
    
     
    
    import org.springframework.jms.support.converter.MessageConversionException;
    
    import org.springframework.stereotype.Component;
    
    @Component
    
    public class JmsListener {
    
    @org.springframework.jms.annotation.JmsListener(destination="tacocloud.order.mytest3")
    
    public void receivejms13(Organization fromMessage) throws MessageConversionException, JMSException{
    
    System.out.println("推送"+fromMessage);
    
      }
    }

    这种模式采用的是@JmsListener注解去指定目的地,相当于加了一个监听器,当有消息发送来的时候,该方法被调用

     

    拉取模式和推送模式

    1. 拉取模式,消费者是主动地,需要主动调用消费消息的方法去拉取消息,若存在消息,拉取,若没有消息,等待,线程一致被占用,一直到拉取到消息
    2. 推送模式,生产者是主动的。监听器一直在舰艇生产者的消息,生成者发送消息,被监听器监听到,调用消费者方法消费。这种方法不会一致占用资源

    两种模式优劣:

    比如说在蛋糕店订蛋糕,客人订蛋糕,蛋糕店接受订单。若采取拉取模式,蛋糕店作为消息的消费者,是主动的去获取订单,那么他们可以在一个订单做完了,再去拉取下一个订单。不会出现一下子来大量订单使得无法完成。

    比如说快餐店外卖。快餐店作为消息的消费者。正常情况下不用考虑来不及的情况。可以采取推送模式。顾客点单,快餐店就接收。

     

    6.发布-订阅模式

    前面我们讲的都是顶对点模式,现在看怎么用发布订阅模式。在点对点的基础上。

    1) 添加配置

    spring:
    
    jms:
    
    pub-sub-domain: true

    2) 发送消息-前面点对点模式Destination 采用ActiveMQQueue

    Destination d = new ActiveMQQueue("tacocloud.order.jms2");

    现在

      Destination dest = new ActiveMQTopic("tacocloud.order.dingyue1");

     

    3) 接收消息-只能采用推送模式

    package tacos;
    
     
    
    import javax.jms.JMSException;
    
     
    
    import org.springframework.jms.support.converter.MessageConversionException;
    
    import org.springframework.stereotype.Component;
    
     
    
    @Component
    
    public class JmsListener {
    
     
    
    @org.springframework.jms.annotation.JmsListener(destination="tacocloud.order.mytest3")
    
     
    
    @org.springframework.jms.annotation.JmsListener(destination="tacocloud.order.dingyue1")
    
    public void receivejms14(Organization fromMessage) throws MessageConversionException, JMSException{
    
    System.out.println("订阅模式消费者1"+fromMessage);
    
    }
    
    @org.springframework.jms.annotation.JmsListener(destination="tacocloud.order.dingyue1")
    
    public void receivejms15(Organization fromMessage) throws MessageConversionException, JMSException{
    
    System.out.println("订阅模式消费者2"+fromMessage);
    
    }
    }

     

    点对点/发布订阅两种模式由生产者端的代码来决定

    拉取/推送两种消费方式由消费者端代码来决定

     

    JMS缺点:只能作用于JAVA应用中。

     

  • 相关阅读:
    OpenCV学习(7)--
    OpenCV学习(6)--更多形态转化、Hit-or-Miss变换、Hit-or-Miss变换、图像金字塔
    Linux基本操作
    设计模式
    利用Python进行数据分析:【Matplotlib】
    利用Python进行数据分析:【Pandas】(Series+DataFrame)
    利用Python进行数据分析:【NumPy】
    利用Python进行数据分析:【IPython】
    数据结构与算法(C/C++版)【排序】
    《操作系统》学习笔记
  • 原文地址:https://www.cnblogs.com/jthr/p/13786595.html
Copyright © 2011-2022 走看看