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. Django更换数据库和迁移数据方案

    前言 双十一光顾着买东西都没怎么写文章,现在笔记里还有十几篇半成品文章没写完- 今天来分享一下 Django 项目切换数据库和迁移数据的方案,网络上找到的文章方法不一,且使用中容易遇到各类报错,本文根 ...

  2. MongoDB 数据库的学习

    一.MongoDB的简介 1.MongoDB是什么? MongoDB 是由 C++ 语言编写的,基于分布式文件存储的数据库,是一个介于关系数据库和非关系数据库之间的产品,是最接近于关系型数据库的 No ...

  3. Python基础之网络编程:2、OSI协议之七层协议

    目录 Python基础之网络编程 一.网络编程前戏 二.OSI七层协议 简介: 1.物理连接层 2.数据链路层 网络相关专业名词 3.网络层 4.传输层 Python基础之网络编程 一.网络编程前戏 ...

  4. Cacheable VS Non-Cacheable

    1 基本概念 在嵌入式软件开发中,经常会碰到说某块内存是cache的,还是non-cache的,它们究竟是什么意思?分别用在什么场景?non-cache和cache的内存区域怎么配置?这篇博文将会围绕 ...

  5. 第2-4-1章 规则引擎Drools介绍-业务规则管理系统-组件化-中台

    目录 规则引擎 Drools 1. 问题引出 2. 规则引擎概述 2.1 什么是规则引擎 2.2 使用规则引擎的优势 2.3 规则引擎应用场景 2.4 Drools介绍 规则引擎 Drools 全套代 ...

  6. IIS部署WebApi跨域不生效

    在IIS8.5上部署了WebApi程序,但是跨域不生效检查了前端和后端都没有问题. 后面才发现在应用程序池中需要设置为集成模式.经典模式下不能正常使用

  7. POST请求发送的表单数据和json数据的区别及python代码实现

    前言 这篇博客会介绍最常见post 请求form表单数据和json数据 数据类型之间的区别, urllib代码的实现(python), requests库实现, 以及如何使用postman软件发送这些 ...

  8. .NET 6 实现滑动验证码(四)、扩展类

    为了能够通过配置文件(appsettings.json)或通过代码进行背景图片与模板进行配置.可自定义资源类型.自定义验证规则,本节创建一些扩展类,用来实现这些功能. 上一节内容:NET 6 实现滑动 ...

  9. 彻底理解Python中的闭包和装饰器(上)

    什么是闭包 闭包(Closure)其实并不是Python独有的特性,很多语言都有对闭包的支持.(当然,因为Python是笔者除C/C++之外学习的第二门语言,所以也是第一次遇到闭包.)简而言之,闭包实 ...

  10. webShell攻击及防御

    最近公司项目也是经常被同行攻击,经过排查,基本定位都是挂马脚本导致,所以针对webShell攻击做一下记录. 首先简单说下 什么是webShell? 利用文件上传,上传了非法可以执行代码到服务器,然后 ...