demo
package org.example.activemq.test;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class Receiver {
public static void main(String[] args) throws Exception {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("my-queue");
MessageConsumer consumer = session.createConsumer(queue);
TextMessage receive = (TextMessage) consumer.receive();
session.commit();
System.out.println(receive.getText());
session.close();
connection.close();
}
}
package org.example.activemq.test;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class Sender {
public static void main(String[] args) throws JMSException, InterruptedException {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
Connection connection = activeMQConnectionFactory.createConnection();
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("my-queue");
MessageProducer producer = session.createProducer(queue);
TextMessage test = session.createTextMessage("Test");
producer.send(test);
session.commit();
session.close();
connection.close();
}
}
整合spring
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"></property>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="activeMQConnectionFactory"></property>
</bean>
<bean name="queue" class="org.apache.activemq.command.ActiveMQQueue" id="activeMQQueue">
<constructor-arg value="sayHello" index="0"></constructor-arg>
</bean>
<bean id="listener" class="org.example.activemq.spring.TestMessageListener"></bean>
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="activeMQConnectionFactory"></property>
<property name="destination" ref="queue"></property>
<property name="messageListener" ref="listener"></property>
</bean>
</beans>
package org.example.activemq.spring;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import javax.jms.*;
public class SpringReceiver {
public static void main(String[] args) throws Exception {
ApplicationContext bf2 = new ClassPathXmlApplicationContext("activeMq/jms.xml");
JmsTemplate jmsTemplate = (JmsTemplate) bf2.getBean("jmsTemplate");
ActiveMQQueue activeMQQueue = (ActiveMQQueue) bf2.getBean("activeMQQueue");
TextMessage receive =(TextMessage)jmsTemplate.receive(activeMQQueue);
System.out.println(receive.getText());
}
}
package org.example.activemq.spring;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.example.MyBeanTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import javax.jms.*;
public class SpringSender {
public static void main(String[] args) throws JMSException, InterruptedException {
ApplicationContext bf2 = new ClassPathXmlApplicationContext("activeMq/jms.xml");
JmsTemplate jmsTemplate = (JmsTemplate) bf2.getBean("jmsTemplate");
ActiveMQQueue activeMQQueue = (ActiveMQQueue) bf2.getBean("activeMQQueue");
while (true) jmsTemplate.send(activeMQQueue, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("Test");
}
});
}
}
package org.example.activemq.spring;
import lombok.SneakyThrows;
import javax.jms.Message;
import javax.jms.TextMessage;
/**
* 使用监听器,不停监听信息状态
*/
public class TestMessageListener implements javax.jms.MessageListener {
@SneakyThrows
@Override
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
System.out.println("我是监听器:" + textMessage.getText());
}
}
源码分析
JmsTemplate
@Override
public void afterPropertiesSet() {
if (getConnectionFactory() == null) {
throw new IllegalArgumentException("Property 'connectionFactory' is required");
}
}
发送
@Override
public void send(final Destination destination, final MessageCreator messageCreator) throws JmsException {
execute(session -> {
doSend(session, destination, messageCreator);
return null;
}, false);
}
@Nullable
public <T> T execute(SessionCallback<T> action, boolean startConnection) throws JmsException {
Assert.notNull(action, "Callback object must not be null");
Connection conToClose = null;
Session sessionToClose = null;
try {
Session sessionToUse = ConnectionFactoryUtils.doGetTransactionalSession(
obtainConnectionFactory(), this.transactionalResourceFactory, startConnection);
if (sessionToUse == null) {
//创建连接
conToClose = createConnection();
//创建会话
sessionToClose = createSession(conToClose);
//是否开启向服务器推送连接信息,只有接受信息时需要,发送不需要
if (startConnection) {
conToClose.start();
}
sessionToUse = sessionToClose;
}
if (logger.isDebugEnabled()) {
logger.debug("Executing callback on JMS Session: " + sessionToUse);
}
//调用回调函数
return action.doInJms(sessionToUse);
}
catch (JMSException ex) {
throw convertJmsAccessException(ex);
}
finally {
//关闭会话,释放连接
JmsUtils.closeSession(sessionToClose);
ConnectionFactoryUtils.releaseConnection(conToClose, getConnectionFactory(), startConnection);
}
}
protected void doSend(Session session, Destination destination, MessageCreator messageCreator)
throws JMSException {
Assert.notNull(messageCreator, "MessageCreator must not be null");
MessageProducer producer = createProducer(session, destination);
try {
Message message = messageCreator.createMessage(session);
if (logger.isDebugEnabled()) {
logger.debug("Sending created message: " + message);
}
doSend(producer, message);
// Check commit - avoid commit call within a JTA transaction.
if (session.getTransacted() && isSessionLocallyTransacted(session)) {
// Transacted session created by this template -> commit.
JmsUtils.commitIfNecessary(session);
}
}
finally {
JmsUtils.closeMessageProducer(producer);
}
}
接收
@Override
@Nullable
public Message receive(Destination destination) throws JmsException {
return receiveSelected(destination, null);
}
@Override
@Nullable
public Message receiveSelected(final Destination destination, @Nullable final String messageSelector) throws JmsException {
return execute(session -> doReceive(session, destination, messageSelector), true);
}
@Nullable
protected Message doReceive(Session session, Destination destination, @Nullable String messageSelector)
throws JMSException {
return doReceive(session, createConsumer(session, destination, messageSelector));
}
@Nullable
protected Message doReceive(Session session, MessageConsumer consumer) throws JMSException {
try {
// Use transaction timeout (if available).
long timeout = getReceiveTimeout();
ConnectionFactory connectionFactory = getConnectionFactory();
JmsResourceHolder resourceHolder = null;
if (connectionFactory != null) {
resourceHolder = (JmsResourceHolder) TransactionSynchronizationManager.getResource(connectionFactory);
}
if (resourceHolder != null && resourceHolder.hasTimeout()) {
timeout = Math.min(timeout, resourceHolder.getTimeToLiveInMillis());
}
Message message = receiveFromConsumer(consumer, timeout);
if (session.getTransacted()) {
// Commit necessary - but avoid commit call within a JTA transaction.
if (isSessionLocallyTransacted(session)) {
// Transacted session created by this template -> commit.
JmsUtils.commitIfNecessary(session);
}
}
else if (isClientAcknowledge(session)) {
// Manually acknowledge message, if any.
if (message != null) {
message.acknowledge();
}
}
return message;
}
finally {
JmsUtils.closeMessageConsumer(consumer);
}
}
和spring-jdbc一样,封装一个通用的模板方法,然后插入一些需要变化的执行操作
监听器
public void afterPropertiesSet() {
//验证connectionFactory
super.afterPropertiesSet();
//验证配置文件
validateConfiguration();
//初始化
initialize();
}
public void initialize() {
// Adapt default cache level.
//适配默认缓级别
if (this.cacheLevel == CACHE_AUTO) {
this.cacheLevel = (getTransactionManager() != null ? CACHE_NONE : CACHE_CONSUMER);
}
// Prepare taskExecutor and maxMessagesPerTask.
synchronized (this.lifecycleMonitor) {
if (this.taskExecutor == null) {
this.taskExecutor = createDefaultTaskExecutor();
}
else if (this.taskExecutor instanceof SchedulingTaskExecutor &&
((SchedulingTaskExecutor) this.taskExecutor).prefersShortLivedTasks() &&
this.maxMessagesPerTask == Integer.MIN_VALUE) {
// TaskExecutor indicated a preference for short-lived tasks. According to
// setMaxMessagesPerTask javadoc, we'll use 10 message per task in this case
// unless the user specified a custom value.
this.maxMessagesPerTask = 10;
}
}
// Proceed with actual listener initialization.
super.initialize();
}
@Override
public void initialize() {
// Set sessionTransacted=true in case of a non-JTA transaction manager.
if (!this.sessionTransactedCalled &&
this.transactionManager instanceof ResourceTransactionManager &&
!TransactionSynchronizationUtils.sameResourceFactory(
(ResourceTransactionManager) this.transactionManager, obtainConnectionFactory())) {
super.setSessionTransacted(true);
}
// Use bean name as default transaction name.
if (this.transactionDefinition.getName() == null) {
String beanName = getBeanName();
if (beanName != null) {
this.transactionDefinition.setName(beanName);
}
}
// Proceed with superclass initialization.
super.initialize();
}
public void initialize() throws JmsException {
try {
//lifecycleMonitor控制生命周期同步处理
synchronized (this.lifecycleMonitor) {
this.active = true;
this.lifecycleMonitor.notifyAll();
}
doInitialize();
}
catch (JMSException ex) {
synchronized (this.sharedConnectionMonitor) {
ConnectionFactoryUtils.releaseConnection(this.sharedConnection, getConnectionFactory(), this.autoStartup);
this.sharedConnection = null;
}
throw convertJmsAccessException(ex);
}
}
@Override
protected void doInitialize() throws JMSException {
synchronized (this.lifecycleMonitor) {
//concurrentConsumers:允许多少session和messageConsumer来接受信息
for (int i = 0; i < this.concurrentConsumers; i++) {
scheduleNewInvoker();
}
}
}
private void scheduleNewInvoker() {
AsyncMessageListenerInvoker invoker = new AsyncMessageListenerInvoker();
//开启一个线程执行,每个线程作为一个独立的接受者循环接受消息
if (rescheduleTaskIfNecessary(invoker)) {
// This should always be true, since we're only calling this when active.
this.scheduledInvokers.add(invoker);
}
}
protected final boolean rescheduleTaskIfNecessary(Object task) {
if (this.running) {
try {
doRescheduleTask(task);
}
catch (RuntimeException ex) {
logRejectedTask(task, ex);
this.pausedTasks.add(task);
}
return true;
}
else if (this.active) {
this.pausedTasks.add(task);
return true;
}
else {
return false;
}
}
@Override
public void run() {
//并发控制
synchronized (lifecycleMonitor) {
activeInvokerCount++;
lifecycleMonitor.notifyAll();
}
boolean messageReceived = false;
try {
//根据每个任务设置的最大处理消息数作不同处理
//<0默认无限制
if (maxMessagesPerTask < 0) {
messageReceived = executeOngoingLoop();
}
else {
int messageCount = 0;
//消息数量控制,一旦超出数量停止循环
while (isRunning() && messageCount < maxMessagesPerTask) {
messageReceived = (
//消息接收
invokeListener()
|| messageReceived);
messageCount++;
}
}
}
catch (Throwable ex) {
//清除资源,如session
clearResources();
if (!this.lastMessageSucceeded) {
// We failed more than once in a row or on startup -
// wait before first recovery attempt.
waitBeforeRecoveryAttempt();
}
this.lastMessageSucceeded = false;
boolean alreadyRecovered = false;
synchronized (recoveryMonitor) {
if (this.lastRecoveryMarker == currentRecoveryMarker) {
handleListenerSetupFailure(ex, false);
recoverAfterListenerSetupFailure();
currentRecoveryMarker = new Object();
}
else {
alreadyRecovered = true;
}
}
if (alreadyRecovered) {
handleListenerSetupFailure(ex, true);
}
}
finally {
synchronized (lifecycleMonitor) {
decreaseActiveInvokerCount();
lifecycleMonitor.notifyAll();
}
if (!messageReceived) {
this.idleTaskExecutionCount++;
}
else {
this.idleTaskExecutionCount = 0;
}
synchronized (lifecycleMonitor) {
if (!shouldRescheduleInvoker(this.idleTaskExecutionCount) || !rescheduleTaskIfNecessary(this)) {
// We're shutting down completely.
scheduledInvokers.remove(this);
if (logger.isDebugEnabled()) {
logger.debug("Lowered scheduled invoker count: " + scheduledInvokers.size());
}
lifecycleMonitor.notifyAll();
clearResources();
}
else if (isRunning()) {
int nonPausedConsumers = getScheduledConsumerCount() - getPausedTaskCount();
if (nonPausedConsumers < 1) {
logger.error("All scheduled consumers have been paused, probably due to tasks having been rejected. " +
"Check your thread pool configuration! Manual recovery necessary through a start() call.");
}
else if (nonPausedConsumers < getConcurrentConsumers()) {
logger.warn("Number of scheduled consumers has dropped below concurrentConsumers limit, probably " +
"due to tasks having been rejected. Check your thread pool configuration! Automatic recovery " +
"to be triggered by remaining consumers.");
}
}
}
}
}
private boolean executeOngoingLoop() throws JMSException {
boolean messageReceived = false;
boolean active = true;
while (active) {
synchronized (lifecycleMonitor) {
boolean interrupted = false;
boolean wasWaiting = false;
//如果当前任务已经处于激活状态,但是却给了暂停终止的命令
while ((active = isActive()) && !isRunning()) {
if (interrupted) {
throw new IllegalStateException("Thread was interrupted while waiting for " +
"a restart of the listener container, but container is still stopped");
}
if (!wasWaiting) {
//如果并非处于等待状态,则说明第一次执行,需要将激活任务数量较少
decreaseActiveInvokerCount();
}
//进入等待,等待任务的恢复命令
wasWaiting = true;
try {
//通过wait等待,等待notify和notifyAll
lifecycleMonitor.wait();
}
catch (InterruptedException ex) {
// Re-interrupt current thread, to allow other threads to react.
Thread.currentThread().interrupt();
interrupted = true;
}
}
if (wasWaiting) {
activeInvokerCount++;
}
if (scheduledInvokers.size() > maxConcurrentConsumers) {
active = false;
}
}
if (active) {
messageReceived = (invokeListener() || messageReceived);
}
}
return messageReceived;
}
private boolean invokeListener() throws JMSException {
this.currentReceiveThread = Thread.currentThread();
try {
//初始化资源,包括创建session和consumer
initResourcesIfNecessary();
boolean messageReceived = receiveAndExecute(this, this.session, this.consumer);
//改变标志位,信息成功处理
this.lastMessageSucceeded = true;
return messageReceived;
}
finally {
this.currentReceiveThread = null;
}
}
protected boolean receiveAndExecute(
Object invoker, @Nullable Session session, @Nullable MessageConsumer consumer)
throws JMSException {
if (this.transactionManager != null) {
// Execute receive within transaction.
//执行事务
TransactionStatus status = this.transactionManager.getTransaction(this.transactionDefinition);
boolean messageReceived;
try {
//接收执行
messageReceived = doReceiveAndExecute(invoker, session, consumer, status);
}
catch (JMSException | RuntimeException | Error ex) {
rollbackOnException(this.transactionManager, status, ex);
throw ex;
}
this.transactionManager.commit(status);
return messageReceived;
}
else {
// Execute receive outside of transaction.
return doReceiveAndExecute(invoker, session, consumer, null);
}
}
protected boolean doReceiveAndExecute(Object invoker, @Nullable Session session,
@Nullable MessageConsumer consumer, @Nullable TransactionStatus status) throws JMSException {
Connection conToClose = null;
Session sessionToClose = null;
MessageConsumer consumerToClose = null;
try {
Session sessionToUse = session;
boolean transactional = false;
if (sessionToUse == null) {
sessionToUse = ConnectionFactoryUtils.doGetTransactionalSession(
obtainConnectionFactory(), this.transactionalResourceFactory, true);
transactional = (sessionToUse != null);
}
if (sessionToUse == null) {
Connection conToUse;
if (sharedConnectionEnabled()) {
conToUse = getSharedConnection();
}
else {
conToUse = createConnection();
conToClose = conToUse;
conToUse.start();
}
sessionToUse = createSession(conToUse);
sessionToClose = sessionToUse;
}
MessageConsumer consumerToUse = consumer;
if (consumerToUse == null) {
consumerToUse = createListenerConsumer(sessionToUse);
consumerToClose = consumerToUse;
}
//接受消息
Message message = receiveMessage(consumerToUse);
if (message != null) {
if (logger.isDebugEnabled()) {
logger.debug("Received message of type [" + message.getClass() + "] from consumer [" +
consumerToUse + "] of " + (transactional ? "transactional " : "") + "session [" +
sessionToUse + "]");
}
//模板方法
messageReceived(invoker, sessionToUse);
boolean exposeResource = (!transactional && isExposeListenerSession() &&
!TransactionSynchronizationManager.hasResource(obtainConnectionFactory()));
if (exposeResource) {
TransactionSynchronizationManager.bindResource(
obtainConnectionFactory(), new LocallyExposedJmsResourceHolder(sessionToUse));
}
try {
//激活监听器
doExecuteListener(sessionToUse, message);
}
catch (Throwable ex) {
if (status != null) {
if (logger.isDebugEnabled()) {
logger.debug("Rolling back transaction because of listener exception thrown: " + ex);
}
status.setRollbackOnly();
}
handleListenerException(ex);
// Rethrow JMSException to indicate an infrastructure problem
// that may have to trigger recovery...
if (ex instanceof JMSException) {
throw (JMSException) ex;
}
}
finally {
if (exposeResource) {
TransactionSynchronizationManager.unbindResource(obtainConnectionFactory());
}
}
// Indicate that a message has been received.
return true;
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Consumer [" + consumerToUse + "] of " + (transactional ? "transactional " : "") +
"session [" + sessionToUse + "] did not receive a message");
}
//接收空消息处理
noMessageReceived(invoker, sessionToUse);
// Nevertheless call commit, in order to reset the transaction timeout (if any).
if (shouldCommitAfterNoMessageReceived(sessionToUse)) {
commitIfNecessary(sessionToUse, null);
}
// Indicate that no message has been received.
return false;
}
}
finally {
JmsUtils.closeMessageConsumer(consumerToClose);
JmsUtils.closeSession(sessionToClose);
ConnectionFactoryUtils.releaseConnection(conToClose, getConnectionFactory(), true);
}
}
protected void doExecuteListener(Session session, Message message) throws JMSException {
if (!isAcceptMessagesWhileStopping() && !isRunning()) {
if (logger.isWarnEnabled()) {
logger.warn("Rejecting received message because of the listener container " +
"having been stopped in the meantime: " + message);
}
rollbackIfNecessary(session);
throw new MessageRejectedWhileStoppingException();
}
try {
invokeListener(session, message);
}
catch (JMSException | RuntimeException | Error ex) {
rollbackOnExceptionIfNecessary(session, ex);
throw ex;
}
commitIfNecessary(session, message);
}
protected void invokeListener(Session session, Message message) throws JMSException {
Object listener = getMessageListener();
if (listener instanceof SessionAwareMessageListener) {
doInvokeListener((SessionAwareMessageListener) listener, session, message);
}
else if (listener instanceof MessageListener) {
doInvokeListener((MessageListener) listener, message);
}
else if (listener != null) {
throw new IllegalArgumentException(
"Only MessageListener and SessionAwareMessageListener supported: " + listener);
}
else {
throw new IllegalStateException("No message listener specified - see property 'messageListener'");
}
}
protected void doInvokeListener(SessionAwareMessageListener listener, Session session, Message message)
throws JMSException {
Connection conToClose = null;
Session sessionToClose = null;
try {
Session sessionToUse = session;
if (!isExposeListenerSession()) {
// We need to expose a separate Session.
conToClose = createConnection();
sessionToClose = createSession(conToClose);
sessionToUse = sessionToClose;
}
// Actually invoke the message listener...
//执行监听器
listener.onMessage(message, sessionToUse);
// Clean up specially exposed Session, if any.
if (sessionToUse != session) {
if (sessionToUse.getTransacted() && isSessionLocallyTransacted(sessionToUse)) {
// Transacted session created by this container -> commit.
JmsUtils.commitIfNecessary(sessionToUse);
}
}
}
finally {
JmsUtils.closeSession(sessionToClose);
JmsUtils.closeConnection(conToClose);
}
}