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:\DevTools\apache-artemis-2.6.3-bin

执行 cmd

cd /d D:\DevTools\apache-artemis-2.6.3-bin\apache-artemis-2.6.3\bin

artemis create D:\DevTools\apache-artemis-2.6.3-bin\myartemis

//需要设置一个账号

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:\DevTools\apache-artemis-2.6.3-bin\myartemis\bin

启动实例

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;

}

接收消息有两个方法receive和receiveAndConvert,前者返回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应用中。

spring in action day-06 JMS -ActiveMQ Artemi的更多相关文章

  1. JMS - ActiveMQ集成Spring

    下面是ActiveMQ官网提供的文档.http://activemq.apache.org/spring-support.html 下面是我添加的一些dependency: <!-- jms a ...

  2. Spring in action记录

    最近一段时间重新学习了一遍SPRING,现在对这些笔记整理一下,一来算是对之前的学习有一个交代,二来当是重新学习一次,三来可以留下备份 这次学习中以SPRING IN ACTION 4这学习资料,整书 ...

  3. SpringBoot使用JMS(activeMQ)的两种方式 队列消息、订阅/发布

    刚好最近同事问我activemq的问题刚接触所以分不清,前段时间刚好项目中有用到,所以稍微整理了一下,仅用于使用 1.下载ActiveMQ 地址:http://activemq.apache.org/ ...

  4. 1、Spring In Action 4th笔记(1)

    Spring In Action 4th笔记(1) 2016-12-28 1.Spring是一个框架,致力于减轻JEE的开发,它有4个特点: 1.1 基于POJO(Plain Ordinary Jav ...

  5. spring in action 4th --- quick start

    读spring in action. 环境搭建 quick-start依赖注入 面向切面 1.环境搭建 jdk1.8 gradle 2.12 Intelij idea 2016.2.1 1.1创建一个 ...

  6. ssh整合随笔(注解方式,Spring 管理action)

    Web.xml<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi=" ...

  7. Spring in Action 4th 学习笔记 之 AOP

    前提:本文中的AOP仅限于Spring AOP. 先说说为什么需要AOP 最简单的一个例子就是日志记录,如果想记录一些方法的执行情况,最笨的办法就是修改每一个需要记录的方法.但这,真的很笨... 好的 ...

  8. 学习spring in action 第一天

    这段时间,开始学习java吧,因为C sharp 学习了java的大量语法格式,所以,留意下,就不会错了,java 有的c sharp也有,而且之前我也学习过java的桌面开发,但是一下子上来就要自己 ...

  9. spring in action学习笔记十五:配置DispatcherServlet和ContextLoaderListener的几种方式。

    在spring in action中论述了:DispatcherServlet和ContextLoaderListener的关系,简言之就是DispatcherServlet是用于加载web层的组件的 ...

  10. spring in action 学习笔记十四:用纯注解的方式实现spring mvc

    在讲用纯注解的方式实现springmvc之前先介绍一个类:AbstractAnnotationDispatcherServletInitializer.这个类的作用是:任何一个类继承AbstractA ...

随机推荐

  1. WebKit策略:<foreignObject>可用于绘制svg中的html标签,但与<use>搭配不生效

    在<svg>里面可以利用<foreignObject>绘制html标签,原本是我在iconfont采用Font class方式引入svg的无奈之举. 起初的设计是所有icon先 ...

  2. 微信小程序的学习(二)

    一.数据绑定 1.数据绑定的基本原则 在 data 中定义数据 在 wxml 中使用数据 2.如何在 data 里面定义数据? 在页面对应的 .js 文件中,把数据定义到 data 对象中即可: 3. ...

  3. C#winform使用NOPI读取Excel读取图片

    需求:在Winform使用NOPI做导入时候,需要导入数据的同时导入图片. 虽然代码方面不适用(我好像也没仔细看过代码),但是感谢大佬给了灵感http://www.wjhsh.net/IT-Ramon ...

  4. 关于python3调用matplotlib中文乱码问题

    问题描述 我用来绘制柱形图,横坐标上面的数据, 但是网上大部分说的都是更改横纵坐标标签的乱码问题,而不是横坐标数据乱码问题 解决办法 更改横纵坐标上标签的中文不乱码 import matplotlib ...

  5. 在实际应用中联合体union的妙用

    关键字union,又称为联合体.共用体,联合体的声明和结构体类似,但是它的行为方式又和结构体不同,这里的行为方式主要指的是其在内存中的体现,结构体中的成员每一个占据不同的内存空间,而联合体中的所有成员 ...

  6. Java常用开发文档及工具

    一.实用工具/网站 1.PHP中文网:https://www.php.cn/ 2.Json工具:http://www.bejson.com/ 3.IT大哥导航:https://itdage.com/ ...

  7. python注释、变量、数据类型详细

    目录 1.python注释 2.PEP8规范 3.变量与常量 1.python中的变量 2.变量名的命名规范 3.常量的基本使用 1.python注释 什么是注释? 注释是对代码的解释说明,写注释是为 ...

  8. 教你铁威马NAS中如何进行阵列升级

    磁盘阵列 (RAID) 是磁盘阵列的管理工具.当TNAS 中安装的硬盘多于1个时,组建适当的磁盘阵列能提高硬盘的存储效率,提高数据的安全性. 磁盘阵列升级,比如,将原来是RAID 0 或者RAID 1 ...

  9. DID 2022-12-02

    DID第二节课 最低工资对就业率影响(DID) 宾夕法尼亚VS新泽西的快餐店,用边界的好处:在用最低工资法之前,两地工资情况差不多,DID需要两期,92年11月实施,之前之后做电话访问. 数据越全的估 ...

  10. python 爬站长素材网页图片

    一.我们要用python第三方库: import requests import re 二.找到自己感兴趣的网页图片: for i in range(1,2): url = "https:/ ...