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:\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://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个重载方法
- 不带目的地参数
- 带Destination 参数,里面可以包含目的地和其它的一些信息
- 待String参数,也就是目的地
5.接收JMS消息(拉取模式)
发送消息的条件
- 配置默认目的地 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方法获取里面的数据。看上面的第二个接收消息方法)
- 接收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注解去指定目的地,相当于加了一个监听器,当有消息发送来的时候,该方法被调用
拉取模式和推送模式
- 拉取模式,消费者是主动地,需要主动调用消费消息的方法去拉取消息,若存在消息,拉取,若没有消息,等待,线程一致被占用,一直到拉取到消息
- 推送模式,生产者是主动的。监听器一直在舰艇生产者的消息,生成者发送消息,被监听器监听到,调用消费者方法消费。这种方法不会一致占用资源
两种模式优劣:
比如说在蛋糕店订蛋糕,客人订蛋糕,蛋糕店接受订单。若采取拉取模式,蛋糕店作为消息的消费者,是主动的去获取订单,那么他们可以在一个订单做完了,再去拉取下一个订单。不会出现一下子来大量订单使得无法完成。
比如说快餐店外卖。快餐店作为消息的消费者。正常情况下不用考虑来不及的情况。可以采取推送模式。顾客点单,快餐店就接收。
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的更多相关文章
- JMS - ActiveMQ集成Spring
下面是ActiveMQ官网提供的文档.http://activemq.apache.org/spring-support.html 下面是我添加的一些dependency: <!-- jms a ...
- Spring in action记录
最近一段时间重新学习了一遍SPRING,现在对这些笔记整理一下,一来算是对之前的学习有一个交代,二来当是重新学习一次,三来可以留下备份 这次学习中以SPRING IN ACTION 4这学习资料,整书 ...
- SpringBoot使用JMS(activeMQ)的两种方式 队列消息、订阅/发布
刚好最近同事问我activemq的问题刚接触所以分不清,前段时间刚好项目中有用到,所以稍微整理了一下,仅用于使用 1.下载ActiveMQ 地址:http://activemq.apache.org/ ...
- 1、Spring In Action 4th笔记(1)
Spring In Action 4th笔记(1) 2016-12-28 1.Spring是一个框架,致力于减轻JEE的开发,它有4个特点: 1.1 基于POJO(Plain Ordinary Jav ...
- spring in action 4th --- quick start
读spring in action. 环境搭建 quick-start依赖注入 面向切面 1.环境搭建 jdk1.8 gradle 2.12 Intelij idea 2016.2.1 1.1创建一个 ...
- ssh整合随笔(注解方式,Spring 管理action)
Web.xml<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi=" ...
- Spring in Action 4th 学习笔记 之 AOP
前提:本文中的AOP仅限于Spring AOP. 先说说为什么需要AOP 最简单的一个例子就是日志记录,如果想记录一些方法的执行情况,最笨的办法就是修改每一个需要记录的方法.但这,真的很笨... 好的 ...
- 学习spring in action 第一天
这段时间,开始学习java吧,因为C sharp 学习了java的大量语法格式,所以,留意下,就不会错了,java 有的c sharp也有,而且之前我也学习过java的桌面开发,但是一下子上来就要自己 ...
- spring in action学习笔记十五:配置DispatcherServlet和ContextLoaderListener的几种方式。
在spring in action中论述了:DispatcherServlet和ContextLoaderListener的关系,简言之就是DispatcherServlet是用于加载web层的组件的 ...
- spring in action 学习笔记十四:用纯注解的方式实现spring mvc
在讲用纯注解的方式实现springmvc之前先介绍一个类:AbstractAnnotationDispatcherServletInitializer.这个类的作用是:任何一个类继承AbstractA ...
随机推荐
- 4.mysql-进阶
1.事务 将多个操作步骤变成一个事务,任何一个步骤失败,则回滚到事务的所有步骤之前状态,大白话:要成功都成功:要失败都失败. 如转账操作,A扣钱.B收钱,必须两个步骤都成功,才认为转账成功 innod ...
- Day17:稀疏数组的超细详解
稀疏数组的超细详解 一个含有大量重复元素的二维数组,我们可以提取其有效元素,压缩空间,整合为一个稀疏数组. 例如一个五子棋棋盘,我们将棋盘看作为一个二维数组,没有棋子的位置为0:黑棋为1:白棋为2: ...
- 为什么Linux需要虚拟内存 [转载好文]
操作系统中的 CPU 和主内存(Main memory)都是稀缺资源,所有运行在当前操作系统的进程会共享系统中的 CPU 和内存资源,操作系统会使用 CPU 调度器分配 CPU 时间1并引入虚拟内存系 ...
- (C++) std::move std::forward及使用
概念 std::ref :针对std::thread,需要把实参显式转换为引用类型: std::move :无条件把参数转换为右值:但是右值赋值给新变量时,实际还要看是否满足右值条件,如const s ...
- MySQL 的 NULL 值是怎么存储的?
大家好,我是小林. 之前有位读者在面字节的时候,被问到这么个问题: 如果你知道 MySQL 一行记录的存储结构,那么这个问题对你没什么难度. 如果你不知道也没关系,这次我跟大家聊聊 MySQL 一行记 ...
- Android 内存缓存框架 LruCache 的实现原理,手写试试?
本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 前言 大家好,我是小彭. 在之前的文章里,我们聊到了 LRU 缓存淘汰算法,并且分析 Java 标准库中支持 ...
- Typora快捷键--实用
一.字体编辑 大小:ctr + 数字 或 ctr + 加减号 或 ### 加粗:ctr + b 倾斜:ctr + i 下划线:ctr + u 删除线:alt + shift + 5 上标:^ + 字体 ...
- 分享项目中在用的asp.net下载业务的服务端基类(支持客户端显示下载百分比进度,支持并发数控制,支持限速)
/// <summary> /// 功能简介:asp.net的下载业务的服务端基类(支持客户端显示下载百分比进度,支持并发数控制,支持限速) /// 创建时间:2015-11-20 /// ...
- [OpenCV实战]40 计算机视觉工具对比
文章目录 1 简介 2 适用于计算机视觉的MATLAB 2.1 为什么要使用MATLAB进行计算机视觉:优点 2.2 为什么不应该将MATLAB用于计算机视觉:缺点 3 适用于计算机视觉的OpenCV ...
- 基于Java的高并发多线程分片断点下载
基于Java的高并发多线程分片断点下载 首先直接看测试情况: 单线程下载72MB文件 7线程并发分片下载72MB文件: 下载效率提高2-3倍,当然以上测试结果还和设备CPU核心数.网络带宽息息相关. ...