Springboot整合activemq
项目结构
activemq-c是消费者端 ,activemq-p是生产者端
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
配置文件(application.properties)代码
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
下面开始连接activemq,并生产消息和消费消息
- 设置连接工厂(消费者和生产者都需要配置)
@Value("{spring.activemq.user}")
public String userName;
@Value("${spring.activemq.password}")
public String password;
@Value("${spring.activemq.broker-url}")
public String brokerUrl;
@Bean
public ActiveMQConnectionFactory activeMQConnectionFactory(RedeliveryPolicy redeliveryPolicy){
ActiveMQConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory(this.userName,this.password,this.brokerUrl);
activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);
return activeMQConnectionFactory;
}
- 设置消息重发机制(连接工厂参数就只该参数,不是必须设置)
@Bean
public RedeliveryPolicy redeliveryPolicy(){
RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
redeliveryPolicy.setUseExponentialBackOff(true); //是否在每次尝试重新发送失败后,增加等待时间
redeliveryPolicy.setMaximumRedeliveries(10); //重发次数,默认为6 这里设置为10
redeliveryPolicy.setInitialRedeliveryDelay(1); //重发时间间隔,这里设置为1秒
//第一次失败后重新发送之前等待500毫秒,第二次失败再等待500 * 2毫秒,这里的2就是value
redeliveryPolicy.setBackOffMultiplier(2);
//是否避免消息碰撞
redeliveryPolicy.setUseCollisionAvoidance(false);
//设置重发最大拖延时间-1 表示没有拖延只有UseExponentialBackOff(true)为true时生效
redeliveryPolicy.setMaximumRedeliveryDelay(-1);
return redeliveryPolicy;
}
- 设置发送消息的模板(当处于生产者位置时可配置)
/**
* 消息发送模板
* 应答模式有以下集中
* AUTO_ACKNOWLEDGE = 1 自动确认
* CLIENT_ACKNOWLEDGE = 2 客户端手动确认
* DUPS_OK_ACKNOWLEDGE = 3 自动批量确认
* SESSION_TRANSACTED = 0 事务提交并确认
* @param activeMQConnectionFactory
* @return
*/
@Bean
public JmsTemplate jmsTemplate(ActiveMQConnectionFactory activeMQConnectionFactory){
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT); //进行持久化配置 1表示非持久化,2表示持久化
jmsTemplate.setConnectionFactory(activeMQConnectionFactory);
jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE); //设置应答模式 这里设置为自动确认
jmsTemplate.setSessionTransacted(true);
return jmsTemplate;
}
- 若是监听topic消息时需要配置监听容器工厂
/**
* topic模式需要定义监听容器工厂,每个监听clientId都要不一样
* @param connectionFactory
* @return
*/
@Bean
JmsListenerContainerFactory<?> myJmsContainerFactory_A(ConnectionFactory connectionFactory){
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setPubSubDomain(true); //启用订阅模式
factory.setSubscriptionDurable(true); //启用持久化模式
factory.setClientId("XZ_1"); //设置id,只有是消息持久化时需要设置客户端id
return factory;
}
生成者生成消息,下面我写了一个控制层专门接受消息,如果是发送虚拟主题的消息,切记写法要注意,一定是VirtualTopic开头,格式是VirtualTopic.*(activemq默认是VirtualTopic开头,可在activemq.xml配置文件修改,这里不介绍)
/**
* 发送queue消息
* @param text
* @return
*/
@RequestMapping("/send")
public String send(String text){
//test.queue是消息队列
Destination destination = new ActiveMQQueue("test.queue");
producerQueue.send(destination,text);
return "发送成功";
}
/**
* 发送虚拟主体消息
* @param text
* @return
*/
@RequestMapping("/sendVt")
public String sendVt(String text){
Destination destination = new ActiveMQTopic("VirtualTopic.topic"); //固定写法 VirtualTopic.*
producerQueue.send(destination,text);
return "发送成功";
}
/**
* 发布订阅
* @param text
* @return
*/
@RequestMapping("/sendTopic")
public String sendTopic(String text){
Destination destination = new ActiveMQTopic("test.topic");
producerTopic.send(destination,text);
return "发送成功";
}
生产者发送消息,发送消息可用JmsTemplate 也可以用JmsMessagingTemplate,JmsMessagingTemplate是对JmsTemplate 再一次封装,上面我们配置了JmsTemplate ,所以这里使用JmsTemplate 。
@Autowired
private JmsTemplate jmsTemplate;
/**
*发送消息Destination 是表示目的地,也就是发送给哪个队列,text是需要发送的消息
*如果需要发送对象等数据,可灵活的把对象等数据类型转成json格式发送,但是activemq也支持
*发送map、object、text、对象等五种数据类型,如果是对象的话需要实现序列化接口
*/
public void send(Destination destination, final String text){
jmsTemplate.convertAndSend(destination,text);
}
/**
*监听消费者返回的消息,这里的返回不是传统意义上的方法返回,是消费者另外new 了一个
*队列来专门保存返回消息,生产者监听这个队列就可以得到返回的消息了
*/
@JmsListener(destination = "reply.queue")
public void receive(String text){
System.out.println("生成者收到报文" + text);
}
如果是监听queue(队列)的消息,可用下面的方法,如果有多个消费者监听同一个队列,每个队列将平均分配消息,如:consumerA和consumerB同时监听test.queue,如果发送了两条消息,则consumerA和consumerB都获取一条消息
@JmsListener(destination = "test.queue")
@SendTo("reply.queue") //返回消息到队列,供生产者监听时获取返回处理结果
public String receive(TextMessage text, Session session){
try {
System.out.println(this.getClass().getName() + "收到的报文" + text.getText());
} catch (JMSException e) {
e.printStackTrace();
}
//int i = 1/0;
return "ConsumerA==收到";
}
监听topic时需要使用监听容器工厂myJmsContainerFactory_A,myJmsContainerFactory_A是上面配置的。
@JmsListener(destination = "test.topic",containerFactory = "myJmsContainerFactory_A")
public void receive(String text){
System.out.println(this.getClass().getName()+" 收到的报文为:"+text);
}
监听虚拟主题,和虚拟主题发送一样,监听也是有格式要求,一定要注意格式,格式是: Consumer.* .VirtualTopic.* ,同样的Consumer和VirtualTopic是可以在配置文件修改的。
下面是监听虚拟主题
//ConsumerVt_A监听
@JmsListener(destination = "Consumer.A.VirtualTopic.topic") //固定写法 Consumer.*.VirtualTopic.*,VirtualTopic后面的*跟随生产者的名称
public void receive(TextMessage message, Session session){
try {
System.out.println(this.getClass().getName() + message.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
//ConsumerVt_B监听
@JmsListener(destination = "Consumer.A.VirtualTopic.topic")
public void receive(TextMessage message, Session session){
try {
System.out.println(this.getClass().getName() + message.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
//ConsumerVt_ALL监听
@JmsListener(destination = "Consumer.ALL.VirtualTopic.topic")
public void receive(TextMessage message, Session session){
try {
System.out.println(this.getClass().getName() + message.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
注意ConsumerVt_A和ConsumerVt_B监听的对象都是同一个,所以获取的消息时平均分配的,ConsumerVt_ALL是一个人监听一个,所以获得所有的消息,虚拟主题解决了队列不能同时可以平均分配消息又可以获取所有消息的问题
消息持久化,如果需要使用消息持久化,需要配置生产者,注意前面配置JmsTemplate 时,有一个属性是配置消息持久化的
jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT); //进行持久化配置 PERSISTENT表示非持久化,NON_PERSISTENT表示持久化
配置了这个queue就可以持久化消息了,但是topic还不行,注意前面的配置,在配置myJmsContainerFactory_A时,配置了启动持久化属性
factory.setPubSubDomain(true); //启用订阅模式
factory.setSubscriptionDurable(true); //启用持久化模式
factory.setClientId("XZ_2"); //设置id,每个监听的clientID都需要不一样
持久化的方式有好多种,activemq模式的kahadb模式,也可以配置数据库模式,下面演示以下配置mysql持久化,在activemq的conf文件夹线面有个activemq.xml的配置文件,修改一下的内容
<!--注释掉原先默认的kahadb模式
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
-->
启用mysql持久化
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds"/>
</persistenceAdapter>
在broker节点之外创建bean节点,这里需要注意两点
①,数据库需要手动先创建好
②,url后面的relaxAutoCommit=true一定要配置
<bean id="mysql-ds" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activemq?relaxAutoCommit=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
以上就是activemq的简单使用方法