SpringBoot使用JMS消息代理

Java Message Service是一个Java标准,它定义了一套与消息broker交互的通用API。在JMS出现之前,每一种消息broker都有自己独特的一套API,使得应用代码无法在不同的broker之间适用。但是通过JMS,所有与broker交互的代码就可以适用一套通用的API,就像JDBC一样。

Spring对JMS也提供了支持,即JmsTemplate。通过JmsTemplate,我们可以更加方便地向queue和topic发送和接收消息。

本次练习使用JMS代理发布和订阅消息的过程。下面构建一个使用Spring JmsTemplate发布单个消息的应用程序,并使用@JmsListener托管bean的带注释方法对其进行订阅。

参考文档:https://spring.io/guides/gs/messaging-jms/

使用Maven 引入依赖如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-broker</artifactId>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
    </dependencies>

创建一个简单的消息实体类,包含两个字段to和body,以及getter和setter集合,并重写了toString方法:

public class Email {

    private String to;
    private String body;

    public Email() {
    }

    public Email(String to, String body) {
        this.to = to;
        this.body = body;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    @Override
    public String toString() {
        return String.format("Email{to=%s, body=%s}", getTo(), getBody());
    }

}

再定义一个消息接收者,它是消息驱动的类,不需要实现任何特定的接口或具有任何特定名称的方法。JmsListener注解定义的名称destination,表示该方法要参照JmsListenerContainerFactory去使用创建基础消息侦听容器。严格地说,除非需要自定义容器的构建方式,否则不需要最后一个属性,因为Spring Boot会在必要时注册默认工厂。

@Component
public class Receiver {

    @JmsListener(destination = "mailbox", containerFactory = "myFactory")
    public void receiveMessage(Email email) {
        System.out.println("Received <" + email + ">");
    }

}

接下来,使用SpringBoot启动发送消息和消息接收器,启动类:

@SpringBootApplication
@EnableJms
public class SpringBootJmsApplication {

    
    @Bean
    public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        // This provides all boot's default to this factory, including the message converter
        configurer.configure(factory, connectionFactory);
        // You could still override some of Boot's default if necessary.
        return factory;
    }

    @Bean // Serialize message content to json using TextMessage
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }

    public static void main(String[] args) {
        // Launch the application
        ConfigurableApplicationContext context = SpringApplication.run(SpringBootJmsApplication.class, args);

        JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);

        // Send a message with a POJO - the template reuse the message converter
        System.out.println("Sending an email message.");
        jmsTemplate.convertAndSend("mailbox", new Email("info@example.com", "Hello"));
    }
    
}

启动项目,收到消息如下:
Sending an email message.
Received <Email{to=info@example.com, body=Hello}>

@EnableJms触发发现带注释的方法@JmsListener,创建消息监听器容器。这里还定义了一个在接收器注释中myFactory引用的bean JmsListener。因为我们使用DefaultJmsListenerContainerFactoryConfigurerSpring Boot提供的基础结构,所以JmsMessageListenerContainer它与默认情况下引导创建的基础结构相同。

默认MessageConverter能够转换只有基本类型(例如String,Map,Serializable),这里Email类是故意不实现序列化的。要使用Jackson并以文本格式将内容序列化为json(即作为一个TextMessage)。Spring Boot将检测MessageConverter的存在,并将其与默认的JmsTemplate和DefaultJmsListenerContainerFactoryConfigurer创建的任何JmsListenerContainerFactory相关联。

JmsTemplate使消息发送到JMS目的地变得非常简单。在main 运行方法中,启动后,可以使用jmsTemplate发送EmailPOJO。因为我们的自定义MessageConverter已自动关联到它,所以只会生成一个json文档TextMessage。JmsTemplate和ConnectionFactory这两个bean是由Spring Boot自动创建的。

Spring JmsTemplate可以通过它的receive方法直接接收消息,但这只能同步工作,这意味着它会阻塞。这就是为什么建议使用侦听器容器,例如DefaultMessageListenerContainer使用基于缓存的连接工厂,这样就可以以最大的连接效率使用异步消息。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容