spring-jms-activemq集成


spring支持jsm相关消息框架,可以类似于orm框架那样进行aop之后省略事务提交过程

需要的jar包

这里以activemq为例,如果是其他消息容器,请替换第二个jar包

<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-client</artifactId>
			<version>${activemq.version}</version>
		</dependency>
	</dependencies>

配置

@Configuration
@ComponentScan("com.activemq.spring")
@EnableJms// 开启spirngjms配置
public class JavaConfig {
	/**
	 * 初始化连接工厂
	 * @return
	 */
	@Bean
	public ConnectionFactory getConnectionFactory() {
		ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
		// 断开自动重新连接的brokerURL
		// String brokerURL = "failover:(tcp://localhost:61616,tcp://localhost:61616...)";
		String brokerURL = "failover:(tcp://localhost:61616)";
		activeMQConnectionFactory.setBrokerURL(brokerURL);
		return activeMQConnectionFactory;
	}

	/**
	 * 初始化JmsListenerContainer工程,JmsListenerContainer是一个底层的专门用来开启收取监听的实现,有了它就能使用@JmsListener直接监听
	 * @param connectionFactory
	 * @return
	 */
	@Bean
	public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory) {
		DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
		factory.setConnectionFactory(connectionFactory);
		factory.setConcurrency("1-2");// 并发数1表示最小并发数,2表示最大并发数(类似线程池里边核心线程数和最大线程数的概念)
		return factory;
	}

	/**
	 * JmsTemplate用来收发消息
	 * @param connectionFactory
	 * @return
	 */
	@Bean
	public JmsTemplate getJmsTemplate(ConnectionFactory connectionFactory) {
		JmsTemplate JmsTemplate = new JmsTemplate(connectionFactory);
		JmsTemplate.setReceiveTimeout(3000);// 设置请求响应模式下的超时时间
		return JmsTemplate;
	}

	/**
	 * 一个目的队列,这里也可以使用tocpic
	 * @return
	 */
	@Bean
	public Destination sendQueue() {
		Destination queue = new ActiveMQQueue("sendQueue");
		return queue;
	}

	/**
	 * 一个目的队列
	 * @return
	 */
	@Bean
	public Destination sendAndReceiveQueue() {
		Destination queue = new ActiveMQQueue("sendAndReceiveQueue");
		return queue;
	}
}

消息发布者

@Service
public class Publisher {
	@Autowired
	private JmsTemplate jmsTemplate;

	@Resource(name = "sendQueue")
	private Destination sendQueue;

	@Resource(name = "sendAndReceiveQueue")
	private Destination sendAndReceiveQueue;

	public void send() {
		jmsTemplate.send(sendQueue, new MessageCreator() {
			@Override
			public Message createMessage(Session session) throws JMSException {
				TextMessage message = session.createTextMessage();
				message.setText("hello world");
				return message;
			}
		});
	}

	public void sendAndReceive() {
		Message replyMsg = jmsTemplate.sendAndReceive(sendAndReceiveQueue, new MessageCreator() {
			public Message createMessage(Session session) throws JMSException {
				TextMessage objMsg = session.createTextMessage("send and receive");
				String correlationID = UUID.randomUUID().toString();
				System.out.println("correlationID:" + correlationID);
				objMsg.setJMSCorrelationID(correlationID);
				return objMsg;
			}
		});
		/**
		 * 超时
		 */
		if (null != replyMsg) {
			try {
				System.out.println("response:" + ((TextMessage) replyMsg).getText());
			} catch (JMSException e) {
				e.printStackTrace();
			}
		} else {
			System.out.println("timeout");
		}
	}
}

消息消费者

/**
 * 消息接收器
 * @author Administrator
 */
@Service
public class Receiver {
	@JmsListener(destination = "sendQueue")
	public void receiveTextMessage(String msg) {
		System.out.println("Received <" + msg + ">");
	}

	@JmsListener(destination = "sendAndReceiveQueue")
	public void receiveAndSendTextMessage(Session session, TextMessage msg) {
		try {
			MessageProducer producer = session.createProducer(null);
			System.out.println("receive msg:" + msg.getText());

			TextMessage replyMsg = session.createTextMessage();
			replyMsg.setJMSCorrelationID(msg.getJMSCorrelationID());
			replyMsg.setText("reply message");
			producer.send(msg.getJMSReplyTo(), replyMsg);
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
}

主函数

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
		Publisher publisher = context.getBean(Publisher.class);
		publisher.send();
		publisher.sendAndReceive();
		context.close();
	}
}

消息在容器中的生存时间

如果消息发送者在发送响应模式下发送消息后无消费者消费消息,发送者已经响应已经超时并删除了临时队列,此时消费者启动,则消费者会在一个已经删除的临时队列上发送响应消息,会报错

javax.jms.InvalidDestinationException: Cannot publish to a deleted Destination: temp-queue://ID:*******-52945-1551608104122-1:2:1

所以发送响应模式最好设置消息在容器中的生存时间,jms通过设置消息头部信息JMSExpiration来实现,具体参考JMS消息内部结构
在spirng jms架构中需要尽心如下设定
JmsTemplate.setExplicitQosEnabled(true);必须设定为true

/**
	 * JmsTemplate用来收发消息
	 * @param connectionFactory
	 * @return
	 */
	@Bean
	public JmsTemplate getJmsTemplate(ConnectionFactory connectionFactory) {
		JmsTemplate JmsTemplate = new JmsTemplate(connectionFactory);
		// 设置为true,deliveryMode,priority,timeToLive才会起作用
		JmsTemplate.setExplicitQosEnabled(true);
		JmsTemplate.setReceiveTimeout(3000);// 设置请求响应模式下的超时时间
		return JmsTemplate;
	}

设置timeToLive需要通过JmsTemplate进行设置

JmsTemplate.setTimeToLive(3000);

连接的超时时间

如果希望在actimemq连接不上时发送消息不直接阻塞(永久阻塞)则需要使用连接超时,使用failover的参数timeout和maxReconnectAttempts来实现

timeout:默认为-1,单位毫秒,是否允许在重连过程中设置超时时间来中断正在阻塞的发送操作。-1表示不允许,其他表示超时时间。
maxReconnectAttempts:5.6版本之前默认为-1,5.6版本及其以后,默认为0。0表示重连的次数无限,配置大于0可以指定最大重连次数。

String brokerURL = "failover:(tcp://localhost:61616,tcp://localhost:61616)?timeout=3000&maxReconnectAttempts=1";
发布了36 篇原创文章 · 获赞 5 · 访问量 5350

猜你喜欢

转载自blog.csdn.net/weixin_43060721/article/details/88092251
今日推荐