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. <六>指向类成员的指针

    指向类成员(成员变量和成员方法)的指针 1:定义一个指针指向类的普通成员变量 示例代码1 点击查看代码 class Test2{ public: int ma; static int mb; void ...

  2. 5 分钟速通 SVG

    前言 SVG对不少前端来说就是一个熟悉的陌生人,此篇博客是我学习完SVG后做的一个小总结,帮助我快速回忆SVG相关内容. 它不能帮你精通 SVG,但是可以帮你快速了解SVG的一些核心内容,不会迷失在一 ...

  3. 报错:com.mysql.jdbc.MysqlDataTruncation: Data truncation xxxx

    报错 Out of range value for column 'pk' at row 1:表的字段长度不够 Data too long for column 'ip' at row 1:表的字段长 ...

  4. java:绘制图形

    java绘图类:Graphics类 绘图是高级程序中必备的技术,在很多方面都能用到,如:绘制闪屏图片,背景图片和组件外观等. 1.Graphics类 Graphics类是所有图形上下文的抽象基类,Gr ...

  5. python仿写js算法二

    前言 之前写过一篇用python 仿写 js 算法,当时以为大部分语法都已经能很好的在python找到对应的语法结构,直到前几天我用 python 仿写了 慕课网解析视频加密的算法,我发现很多之前没遇 ...

  6. SVNAdmin2 - 基于web的SVN管理系统

    1. 介绍 SVNAdmin2 是一款通过图形界面管理服务端SVN的web程序. 正常情况下配置SVN仓库的人员权限需要登录到服务器手动修改 authz 和 passwd 两个文件,当仓库结构和人员权 ...

  7. <二>vector向量容器

    底层数据结构:动态开辟的数组,每次以原始空间2倍扩容 vector vec; 增加 vec.push_back(100);容器末尾加元素 时间负责度O(1) 可能导致容器扩容 容器中的,对象的构造析构 ...

  8. MySQL简介、下载、密码修改及基本使用

    目录 存取数据的演变史 数据库软件应用史 数据库的本质 数据库的分类 MySQL简介 MySQL基本使用 系统服务的制作 密码相关操作 SQL与NoSQL 数据库重要概念 基本SQL语句 存取数据的演 ...

  9. 史上最小 x86 Linux 模拟器「GitHub 热点速览 v.22.50」

    本周 GitHub Trending 略显冷清,大概是国内的人们开始在养病,而国外的人们开始过圣诞.元旦双节.热度不减的 ChatGPT 依旧占据了本周大半的 GitHub 热点项目,不过本周的特推和 ...

  10. ArcObjects SDK开发 022 开发框架搭建-FrameWorkUI包设计

    1.CommandUIs部分 这部分主要是定义承载Command和Tool的具体UI.如下图所示. 以CommandUI结尾的这几个类都是继承了Framework.Engine里面的ICommandU ...