mq se divide en cola (modo de cola, el productor produce un mensaje, que solo puede ser consumido por un consumidor) tema (modo de publicación / suscripción, el productor produce un mensaje, que puede ser consumido por varios consumidores)
configuración de application.properties
# http port
server.port=9090
env.host.mq=192.168.46.128
#========================================================MQ=================================================#
spring.activemq.broker-url=tcp://${env.host.mq}:61616
spring.activemq.user=admin
spring.activemq.password=admin
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50
#MQ白名单信任
spring.activemq.packages.trust-all=true
clase de configuración mq
package com.wl.dubbo.blog.mq;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import javax.jms.ConnectionFactory;
import javax.jms.Queue;
/**
* Created by wl on 2017/12/28.
*/
@Configuration
@EnableJms
public class MqConfig {
@Value("${spring.activemq.broker-url}")
private String broker_url;
@Value("${spring.activemq.user}")
private String jmsUser;
@Value("${spring.activemq.password}")
private String jsmPass;
private static final String QUEUE_NAME_ = "queue";
private static final String TOPIC_NAME = "orders";
@Bean("queue")
public Queue queueQueue(){
return new ActiveMQQueue(QUEUE_NAME_);
}
@Bean("topicQueue")
public ActiveMQTopic topicQueue(){
return new ActiveMQTopic(TOPIC_NAME);
}
@Bean(name = "activeMQConnectionFactory")
public ActiveMQConnectionFactory activeMQConnectionFactory(){
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(jmsUser,jsmPass,broker_url);
activeMQConnectionFactory.setTrustAllPackages(true);
return activeMQConnectionFactory;
}
@Bean(name = "queueListenerFactory")
public JmsListenerContainerFactory<?> queueListenerFactory(ConnectionFactory activeMQConnectionFactory){
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setPubSubDomain(false);
factory.setConnectionFactory(activeMQConnectionFactory);
return factory;
}
@Bean(name = "topicListenerFactory")
public JmsListenerContainerFactory<DefaultMessageListenerContainer> topicListenerFactory(ConnectionFactory activeMQConnectionFactory){
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setPubSubDomain(true);
factory.setConnectionFactory(activeMQConnectionFactory);
return factory;
}
@Bean
public JmsMessagingTemplate jmsMessagingTemplate(ConnectionFactory activeMQConnectionFactory){
return new JmsMessagingTemplate(activeMQConnectionFactory);
}
}
publicar
package com.wl.dubbo.blog.mq;
import org.apache.activemq.command.ActiveMQTopic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Component;
import javax.jms.Queue;
/**
* Created by wl on 2017/12/28.
*/
@Component
public class ActiveMQSendService {
private static final Logger logger = LoggerFactory.getLogger(ActiveMQSendService.class);
private JmsMessagingTemplate jmsMessagingTemplate;
private Queue queueQueue;
private ActiveMQTopic activeMQTopic;
@Autowired
public ActiveMQSendService(JmsMessagingTemplate jmsMessagingTemplate,
Queue queueQueue,
ActiveMQTopic topicQueue){
this.jmsMessagingTemplate = jmsMessagingTemplate;
this.queueQueue = queueQueue;
this.activeMQTopic = topicQueue;
}
public void sendQueueMessage(String message){
logger.info("send queue:{}",message);
jmsMessagingTemplate.convertAndSend(queueQueue,message);
}
public void sendTopicMessage(String message){
logger.info("send topic:{}",message);
jmsMessagingTemplate.convertAndSend(activeMQTopic,message);
}
}
consumidor
package com.wl.dubbo.blog.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
/**
* Created by wl on 2017/12/28.
*/
@Component
public class ReceiverService {
private static final Logger logger = LoggerFactory.getLogger(ReceiverService.class);
@JmsListener(destination = "queue",containerFactory = "queueListenerFactory")
public void receiveTestQueue(String receiveStr) throws JMSException {
logger.info("=======================queue:{}",receiveStr);
}
@JmsListener(destination = "orders",containerFactory = "topicListenerFactory" )
public void receiveTopicQueue(String receiveStr) throws JMSException {
logger.info("=======================orders:{}",receiveStr);
}
}
Comenzar la clase
package com.wl.dubbo.blog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
/**
* Created by wl on 2018/8/3.
*/
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class, //不使用数据库
},scanBasePackages = "com.wl")
public class Application {
private static final Logger logger = LoggerFactory.getLogger(BlogApplication.class);
public static void main(String[] args) {
SpringApplication app = new SpringApplication(BlogApplication.class);
app.setWebEnvironment(true);
app.run(args);
logger.info("application init success");
}
}
Clase de prueba
package com.wl.dubbo.blog;
import com.wl.dubbo.blog.mq.ActiveMQSendService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Created by wl on 2018/8/27.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest {
@Autowired
private ActiveMQSendService activeMQSendService;
@Test
public void testSendQueue(){
activeMQSendService.sendQueueMessage("queue===============");
}
@Test
public void testSendTopic(){
activeMQSendService.sendTopicMessage("topic================");
}
}
El mensaje del tema anterior no es persistente. Si el mensaje del tema se envía antes de que se inicie la aplicación de consumo, el consumidor no puede consumir el mensaje; y si en el caso de la implementación distribuida de múltiples máquinas, un tema será el mismo La aplicación consume muchas . Resolver los problemas anteriores requiere temas persistentes y el uso de temas virtuales.
persistencia del tema
Modifique la etiqueta de agente activemq.xml en el directorio activemq_home / config para agregar el atributo persistent = "true"
<!--
The <broker> element is used to configure the ActiveMQ broker.
-->
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" persistent="true" dataDirectory="${activemq.data}">
Activemq utiliza kahaDB para datos persistentes de forma predeterminada y se almacena en el directorio acivemq_home / data / kahaDB
La clase mq config modifica JmsListenerContainerFactory del tema
@Bean(name = "topicListenerFactory")
public JmsListenerContainerFactory<DefaultMessageListenerContainer> topicListenerFactory(ConnectionFactory activeMQConnectionFactory){
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setPubSubDomain(true);//"true" for the Publish/Subscribe domain
factory.setSubscriptionDurable(true);// Set this to "true" to register a durable subscription,
factory.setClientId("A");
//
factory.setConnectionFactory(activeMQConnectionFactory);
return factory;
}
El listenerContainerFactory del tema persistente debe establecer setSubscriptionDurable (true) setPubSubDomain (true) y establecer el clientId
Nota: El clientId de listenerContainerFactory requerido por diferentes destinos debe ser diferente, por lo que es mejor nombrar el clientId de acuerdo con el tipo de negocio. El mismo destino en una implementación distribuida, si el clientId es el mismo, la aplicación iniciada más tarde no puede consumir el destino (si la aplicación iniciada antes se cierra, la aplicación iniciada más tarde puede consumir el destino). Por lo tanto, si desea agregar un nuevo consumidor de destino, debe crear un nuevo listenerContainerFactory, y el clientId es diferente
Tema virtual (tema virtual)
El tema virtual se realiza a través de la cola. En la implementación distribuida, el mismo destino no se consumirá repetidamente
El nombre del tema virtual debe comenzar con el prefijo VirtualTopic. (Se puede modificar cambiando la configuración de activemq.xml en activemq_home / conf)
El destino del tema virtual debe comenzar con el prefijo Consumer. *. VirtualTopic. (Se puede modificar cambiando la configuración activemq.xml en activemq_home / conf) * El número es equivalente a agrupar
Ej .: Si el nombre de la cola es VirtualTopic.Orders, el destino es Consumer.A.VirtualTopic.Orders, Consumer.B.VirtualTopic.Orders en una implementación distribuida, Consumer.A.VirtualTopic.Orders solo se consumirán una vez Consumer.B. VirtualTopic. Los pedidos solo se consumirán una vez
mq config se agrega de la siguiente manera
private static final String VIRTUAL_TOPIC_NAME = "VirtualTopic.Orders";
@Bean("virtualTopicQueue")
public ActiveMQTopic virtualTopicQueue(){
return new ActiveMQTopic(VIRTUAL_TOPIC_NAME);
}
publicar enmendado de la siguiente manera
package com.wl.dubbo.blog.mq;
import org.apache.activemq.command.ActiveMQTopic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Component;
import javax.jms.Queue;
/**
* Created by wl on 2017/12/28.
*/
@Component
public class ActiveMQSendService {
private static final Logger logger = LoggerFactory.getLogger(ActiveMQSendService.class);
private JmsMessagingTemplate jmsMessagingTemplate;
private Queue queueQueue;
private ActiveMQTopic topicQueue;
private ActiveMQTopic virtualTopicQueue;
@Autowired
public ActiveMQSendService(JmsMessagingTemplate jmsMessagingTemplate,
Queue queueQueue,
ActiveMQTopic topicQueue,
ActiveMQTopic virtualTopicQueue){
this.jmsMessagingTemplate = jmsMessagingTemplate;
this.queueQueue = queueQueue;
this.topicQueue = topicQueue;
this.virtualTopicQueue = virtualTopicQueue;
}
public void sendQueueMessage(String message){
logger.info("send queue:{}",message);
jmsMessagingTemplate.convertAndSend(queueQueue,message);
}
public void sendTopicMessage(String message){
logger.info("send topic:{}",message);
jmsMessagingTemplate.convertAndSend(topicQueue,message);
}
public void sendVirtualTopicQueue(String message){
logger.info("send virtualTopic:{}",message);
jmsMessagingTemplate.convertAndSend(virtualTopicQueue,message);
}
}
El consumidor agrega el oyente VirtualTopic.Orders
@JmsListener(destination = "Consumer.B.VirtualTopic.Orders",containerFactory = "queueListenerFactory" )
public void receiveTopicVirtualQueue(String receiveStr) throws JMSException {
logger.info("=======================Consumer.B.VirtualTopic.topic:{}",receiveStr);
}
Tenga en cuenta que el containerFactory usado es queueListenerFactory (al contrario del tema, diferentes colas pueden usar el mismo containerFactory)
prueba
@Test
public void testSendVirtualTopic(){
activeMQSendService.sendVirtualTopicQueue("virtualTopic==============");
}
resultado
2018-08-28 00:18:18,814 INFO (DefaultLifecycleProcessor.java:343)- Starting beans in phase 2147483647
2018-08-28 00:18:19,228 INFO (StartupInfoLogger.java:57)- Started ApplicationTest in 6.17 seconds (JVM running for 7.442)
2018-08-28 00:18:19,291 INFO (ActiveMQSendService.java:50)- send virtualTopic:virtualTopic==============
2018-08-28 00:18:22,280 INFO (ReceiverService.java:31)- =======================Consumer.B.VirtualTopic.topic:virtualTopic==============