Spring整合rabbitmq實(shí)踐(一):基礎(chǔ)
Spring整合rabbitmq實(shí)踐(二):擴(kuò)展
4. 源碼解析
4.1. 通過(guò)RabbitTemplate獲取消息
從RabbitTemplate中只有queueName入?yún)⒌姆椒ㄩ_(kāi)始:
@Override
public Message receive(String queueName) {
if (this.receiveTimeout == 0) {
return doReceiveNoWait(queueName);
}
else {
return receive(queueName, this.receiveTimeout);
}
}
receiveTimeOut參數(shù)為0,直接獲取消息,不等待,獲取不到返回null;否則會(huì)等待一段時(shí)間。
進(jìn)入帶有receiveTimeout的receive方法:
@Override
public Message receive(final String queueName, final long timeoutMillis) {
Message message = execute(channel -> {
Delivery delivery = consumeDelivery(channel, queueName, timeoutMillis);
if (delivery == null) {
return null;
}
else {
if (isChannelLocallyTransacted(channel)) {
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
channel.txCommit();
}
else if (isChannelTransacted()) {
ConnectionFactoryUtils.registerDeliveryTag(getConnectionFactory(), channel,
delivery.getEnvelope().getDeliveryTag());
}
else {
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
return buildMessageFromDelivery(delivery);
}
});
logReceived(message);
return message;
}
看到Message是通過(guò)調(diào)用execute方法得到的,進(jìn)到execute方法:
@Override
public <T> T execute(ChannelCallback<T> action) {
return execute(action, getConnectionFactory());
}
@SuppressWarnings("unchecked")
private <T> T execute(final ChannelCallback<T> action, final ConnectionFactory connectionFactory) {
if (this.retryTemplate != null) {
try {
return this.retryTemplate.execute(
(RetryCallback<T, Exception>) context -> doExecute(action, connectionFactory),
(RecoveryCallback<T>) this.recoveryCallback);
}
catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw RabbitExceptionTranslator.convertRabbitAccessException(e);
}
}
else {
return doExecute(action, connectionFactory);
}
}
這里能看到配置RetryTemplate的作用,具體就不管了,找到doExecute方法,Message是從這里得到的:
private <T> T doExecute(ChannelCallback<T> action, ConnectionFactory connectionFactory) {
...
if (channel == null) {
if (isChannelTransacted()) {
resourceHolder = ConnectionFactoryUtils.
getTransactionalResourceHolder(connectionFactory, true, this.usePublisherConnection);
channel = resourceHolder.getChannel();
if (channel == null) {
ConnectionFactoryUtils.releaseResources(resourceHolder);
throw new IllegalStateException("Resource holder returned a null channel");
}
}
else {
connection = ConnectionFactoryUtils.createConnection(connectionFactory,
this.usePublisherConnection); // NOSONAR - RabbitUtils closes
if (connection == null) {
throw new IllegalStateException("Connection factory returned a null connection");
}
try {
channel = connection.createChannel(false);
if (channel == null) {
throw new IllegalStateException("Connection returned a null channel");
}
}
catch (RuntimeException e) {
RabbitUtils.closeConnection(connection);
throw e;
}
}
}
...
try {
...
return action.doInRabbit(channel);
}
catch (Exception ex) {
...
}
finally {
if (!invokeScope) {
if (resourceHolder != null) {
ConnectionFactoryUtils.releaseResources(resourceHolder);
}
else {
RabbitUtils.closeChannel(channel);
RabbitUtils.closeConnection(connection);
}
}
}
}
這個(gè)方法比較長(zhǎng),大體可以了解到,在這個(gè)方法里創(chuàng)建了Connection和Channel,執(zhí)行action.doInRabbit()方法得到Message,關(guān)閉Channel和Connection。
當(dāng)然,這里Connection和Channel的創(chuàng)建和關(guān)閉都不一定是真的創(chuàng)建和關(guān)閉,與具體的實(shí)現(xiàn)有關(guān),比如CachingConnectionFactory,它的實(shí)現(xiàn)就是有緩存的,后面詳述。
action.doInRabbit()方法的實(shí)現(xiàn)邏輯就要再回到上面的receive方法,這里的action就是在那個(gè)receive方法傳入的一個(gè)ChannelCallback的匿名內(nèi)部實(shí)現(xiàn)類。
可以看到最后返回的消息是從Delivery中得到的,那么看下Delivery是怎么來(lái)的:
private Delivery consumeDelivery(Channel channel, String queueName, long timeoutMillis) throws Exception {
Delivery delivery = null;
RuntimeException exception = null;
CompletableFuture<Delivery> future = new CompletableFuture<>();
DefaultConsumer consumer = createConsumer(queueName, channel, future,
timeoutMillis < 0 ? DEFAULT_CONSUME_TIMEOUT : timeoutMillis);
try {
if (timeoutMillis < 0) {
delivery = future.get();
}
else {
delivery = future.get(timeoutMillis, TimeUnit.MILLISECONDS);
}
}
catch (ExecutionException e) {
Throwable cause = e.getCause();
this.logger.error("Consumer failed to receive message: " + consumer, cause);
exception = RabbitExceptionTranslator.convertRabbitAccessException(cause);
throw exception;
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
catch (TimeoutException e) {
// no result in time
}
finally {
if (exception == null || !(exception instanceof ConsumerCancelledException)) {
cancelConsumerQuietly(channel, consumer);
}
}
return delivery;
}
看到future.get(),顯然這是一個(gè)阻塞式的等待返回結(jié)果,receive方法中傳入的receiveTimeout參數(shù)也正是在這里用到的。那么future數(shù)據(jù)自然是在createConsumer()方法中產(chǎn)生的:
private DefaultConsumer createConsumer(final String queueName, Channel channel,
CompletableFuture<Delivery> future, long timeoutMillis) throws Exception {
channel.basicQos(1);
final CountDownLatch latch = new CountDownLatch(1);
DefaultConsumer consumer = new TemplateConsumer(channel) {
@Override
public void handleCancel(String consumerTag) throws IOException {
future.completeExceptionally(new ConsumerCancelledException());
}
@Override
public void handleConsumeOk(String consumerTag) {
super.handleConsumeOk(consumerTag);
latch.countDown();
}
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
throws IOException {
future.complete(new Delivery(consumerTag, envelope, properties, body));
}
};
channel.basicConsume(queueName, consumer);
if (!latch.await(timeoutMillis, TimeUnit.MILLISECONDS)) {
if (channel instanceof ChannelProxy) {
((ChannelProxy) channel).getTargetChannel().close();
}
future.completeExceptionally(
new ConsumeOkNotReceivedException("Blocking receive, consumer failed to consume: " + consumer));
}
return consumer;
}
channel.basicConsume(queueName, consumer)是rabbitmq的api。
4.2. @RabbitListener注解的作用過(guò)程
@RabbitListener(queues = "test_queue_delay")
public void listen(Message message){
...
}
我們可以通過(guò)注解的方式方便地接收消息,那么為什么一個(gè)普通的方法加上@RabbitListener注解就能接收消息了呢?下面進(jìn)入源碼看一下大體流程。
4.2.1. 實(shí)現(xiàn)流程
進(jìn)入@RabbitListener注解源碼,有一段注釋說(shuō)明了這個(gè)注解是怎么被處理的:
Processing of {@code @RabbitListener} annotations is performed by registering a
{@link RabbitListenerAnnotationBeanPostProcessor}. This can be done manually or, more
conveniently, through the {@code <rabbit:annotation-driven/>} element or
{@link EnableRabbit} annotation.
于是找到RabbitListenerAnnotationBeanPostProcessor,
@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
Class<?> targetClass = AopUtils.getTargetClass(bean);
final TypeMetadata metadata = this.typeCache.computeIfAbsent(targetClass, this::buildMetadata);
for (ListenerMethod lm : metadata.listenerMethods) {
for (RabbitListener rabbitListener : lm.annotations) {
processAmqpListener(rabbitListener, lm.method, bean, beanName);
}
}
if (metadata.handlerMethods.length > 0) {
processMultiMethodListeners(metadata.classAnnotations, metadata.handlerMethods, bean, beanName);
}
return bean;
}
它實(shí)現(xiàn)了postProcessAfterInitialization方法,當(dāng)bean初始化完成后,在這里會(huì)獲取到這個(gè)bean的類用戶自己定義的所有添加了@RabbitListener注解的方法,然后調(diào)用processAmqpListener()方法對(duì)這些方法進(jìn)行處理,實(shí)際上是對(duì)方法上的@RabbitListener進(jìn)行處理,一個(gè)方法上可以有多個(gè)@RabbitListener,會(huì)處理多次。
獲取@RabbitListener注解方法的具體過(guò)程看buildMetadata()方法:
private TypeMetadata buildMetadata(Class<?> targetClass) {
Collection<RabbitListener> classLevelListeners = findListenerAnnotations(targetClass);
final boolean hasClassLevelListeners = classLevelListeners.size() > 0;
final List<ListenerMethod> methods = new ArrayList<>();
final List<Method> multiMethods = new ArrayList<>();
ReflectionUtils.doWithMethods(targetClass, method -> {
Collection<RabbitListener> listenerAnnotations = findListenerAnnotations(method);
if (listenerAnnotations.size() > 0) {
methods.add(new ListenerMethod(method,
listenerAnnotations.toArray(new RabbitListener[listenerAnnotations.size()])));
}
if (hasClassLevelListeners) {
RabbitHandler rabbitHandler = AnnotationUtils.findAnnotation(method, RabbitHandler.class);
if (rabbitHandler != null) {
multiMethods.add(method);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
if (methods.isEmpty() && multiMethods.isEmpty()) {
return TypeMetadata.EMPTY;
}
return new TypeMetadata(
methods.toArray(new ListenerMethod[methods.size()]),
multiMethods.toArray(new Method[multiMethods.size()]),
classLevelListeners.toArray(new RabbitListener[classLevelListeners.size()]));
}
在這個(gè)方法里面,找出了所有加了@RabbitListener注解的方法。
其實(shí)通過(guò)這個(gè)方法可以看到@RabbitListener的另一種使用方式,可以在類上加@RabbitListener注解,然后在方法上加@RabbitHandler注解,如果采用這種方式會(huì)processMultiMethodListeners()方法來(lái)處理這些方法。
這里我們只看processAmqpListener()方法,看它是怎么處理上面找到的這些方法的,
protected void processAmqpListener(RabbitListener rabbitListener, Method method, Object bean, String beanName) {
Method methodToUse = checkProxy(method, bean);
MethodRabbitListenerEndpoint endpoint = new MethodRabbitListenerEndpoint();
endpoint.setMethod(methodToUse);
processListener(endpoint, rabbitListener, bean, methodToUse, beanName);
}
將每一個(gè)加@RabbitListener注解的方法構(gòu)造一個(gè)MethodRabbitListenerEndpoint,然后調(diào)用processListener()方法:
protected void processListener(MethodRabbitListenerEndpoint endpoint, RabbitListener rabbitListener, Object bean,
Object adminTarget, String beanName) {
...
RabbitListenerContainerFactory<?> factory = null;
String containerFactoryBeanName = resolve(rabbitListener.containerFactory());
if (StringUtils.hasText(containerFactoryBeanName)) {
Assert.state(this.beanFactory != null, "BeanFactory must be set to obtain container factory by bean name");
try {
factory = this.beanFactory.getBean(containerFactoryBeanName, RabbitListenerContainerFactory.class);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanInitializationException("Could not register rabbit listener endpoint on [" +
adminTarget + "] for bean " + beanName + ", no " + RabbitListenerContainerFactory.class.getSimpleName() + " with id '" +
containerFactoryBeanName + "' was found in the application context", ex);
}
}
this.registrar.registerEndpoint(endpoint, factory);
這個(gè)方法很長(zhǎng),前面省略的部分是讀取@RabbitListener注解中的值,設(shè)置到endpoint中去。直接看最后一段,endpoint的屬性都設(shè)置完了之后,獲取我們配置的RabbitListenerContainerFactory bean,然后調(diào)用RabbitListenerEndpointRegistrar類的registerEndpoint()方法:
public void registerEndpoint(RabbitListenerEndpoint endpoint, RabbitListenerContainerFactory<?> factory) {
Assert.notNull(endpoint, "Endpoint must be set");
Assert.hasText(endpoint.getId(), "Endpoint id must be set");
// Factory may be null, we defer the resolution right before actually creating the container
AmqpListenerEndpointDescriptor descriptor = new AmqpListenerEndpointDescriptor(endpoint, factory);
synchronized (this.endpointDescriptors) {
if (this.startImmediately) { // Register and start immediately
this.endpointRegistry.registerListenerContainer(descriptor.endpoint,
resolveContainerFactory(descriptor), true);
}
else {
this.endpointDescriptors.add(descriptor);
}
}
}
這里根據(jù)startImmediately看是否需要立刻注冊(cè)endpoint,或者先將其添加到一個(gè)List,稍后統(tǒng)一注冊(cè)。
對(duì)于統(tǒng)一注冊(cè)的實(shí)現(xiàn),RabbitListenerAnnotationBeanPostProcessor類除了實(shí)現(xiàn)BeanPostProcessor以外,還實(shí)現(xiàn)了SmartInitializingSingleton接口,所以當(dāng)RabbitListenerAnnotationBeanPostProcessor這個(gè)bean實(shí)例化完成之后會(huì)調(diào)用它的afterSingletonsInstantiated()方法
@Override
public void afterSingletonsInstantiated() {
...
// Actually register all listeners
this.registrar.afterPropertiesSet();
...
}
因?yàn)橹耙呀?jīng)將所有的endpoint添加到了RabbitListenerEndpointRegistrar類中的一個(gè)List中了,所以這里調(diào)用RabbitListenerEndpointRegistrar類的afterPropertiesSet()方法進(jìn)行統(tǒng)一注冊(cè):
@Override
public void afterPropertiesSet() {
registerAllEndpoints();
}
不管是單獨(dú)注冊(cè)endpoint還是統(tǒng)一注冊(cè),調(diào)用的是同樣的方法,所以看統(tǒng)一注冊(cè)的registerAllEndpoints()方法就行了:
protected void registerAllEndpoints() {
synchronized (this.endpointDescriptors) {
for (AmqpListenerEndpointDescriptor descriptor : this.endpointDescriptors) {
this.endpointRegistry.registerListenerContainer(
descriptor.endpoint, resolveContainerFactory(descriptor));
}
this.startImmediately = true; // trigger immediate startup
}
}
這里就是一個(gè)簡(jiǎn)單的for循環(huán),一個(gè)一個(gè)注冊(cè),具體是怎么注冊(cè)的,再跟蹤registerListenerContainer()方法,直到進(jìn)入下面這個(gè)方法:
public void registerListenerContainer(RabbitListenerEndpoint endpoint, RabbitListenerContainerFactory<?> factory,
boolean startImmediately) {
Assert.notNull(endpoint, "Endpoint must not be null");
Assert.notNull(factory, "Factory must not be null");
String id = endpoint.getId();
Assert.hasText(id, "Endpoint id must not be empty");
synchronized (this.listenerContainers) {
Assert.state(!this.listenerContainers.containsKey(id),
"Another endpoint is already registered with id '" + id + "'");
MessageListenerContainer container = createListenerContainer(endpoint, factory);
this.listenerContainers.put(id, container);
if (StringUtils.hasText(endpoint.getGroup()) && this.applicationContext != null) {
List<MessageListenerContainer> containerGroup;
if (this.applicationContext.containsBean(endpoint.getGroup())) {
containerGroup = this.applicationContext.getBean(endpoint.getGroup(), List.class);
}
else {
containerGroup = new ArrayList<MessageListenerContainer>();
this.applicationContext.getBeanFactory().registerSingleton(endpoint.getGroup(), containerGroup);
}
containerGroup.add(container);
}
if (startImmediately) {
startIfNecessary(container);
}
}
}
可見(jiàn),注冊(cè)endpoint,實(shí)際上就是RabbitListenerContainerFactory將每一個(gè)endpoint都創(chuàng)建成MessageListenerContainer(具體創(chuàng)建過(guò)程,由RabbitListenerContainerFactory類自己去完成),然后根據(jù)startImmediately參數(shù)判斷是否調(diào)用startIfNecessary()方法立即啟動(dòng)MessageListenerContainer。
實(shí)際接收消息是由這個(gè)MessageListenerContainer來(lái)做的,而MessageListenerContainer接口中有一個(gè)接口方法來(lái)設(shè)置MessageListener,
/**
* Setup the message listener to use. Throws an {@link IllegalArgumentException}
* if that message listener type is not supported.
* @param messageListener the {@code object} to wrapped to the {@code MessageListener}.
*/
void setupMessageListener(Object messageListener);
MessageListener將會(huì)調(diào)用我們加了@RabbitListener注解的方法處理消息,
/**
* Listener interface to receive asynchronous delivery of Amqp Messages.
*
* @author Mark Pollack
* @author Gary Russell
*/
@FunctionalInterface
public interface MessageListener {
void onMessage(Message message);
}
或者是ChannelAwareMessageListener接口類來(lái)調(diào)用我們的方法,
/**
* A message listener that is aware of the Channel on which the message was received.
*
* @author Mark Pollack
* @author Gary Russell
*/
@FunctionalInterface
public interface ChannelAwareMessageListener {
/**
* Callback for processing a received Rabbit message.
* <p>Implementors are supposed to process the given Message,
* typically sending reply messages through the given Session.
* @param message the received AMQP message (never <code>null</code>)
* @param channel the underlying Rabbit Channel (never <code>null</code>)
* @throws Exception Any.
*/
void onMessage(Message message, Channel channel) throws Exception;
}
這樣接收并處理消息的所有工作就完成了。
如果不立即啟動(dòng)MessageListenerContainer,RabbitListenerEndpointRegistry也實(shí)現(xiàn)了SmartLifecycle接口,所以在spring context refresh的最后一步會(huì)去調(diào)用start()方法:
@Override
public void start() {
for (MessageListenerContainer listenerContainer : getListenerContainers()) {
startIfNecessary(listenerContainer);
}
}
可以看到在這里統(tǒng)一啟動(dòng)了所有的MessageListenerContainer,
private void startIfNecessary(MessageListenerContainer listenerContainer) {
if (this.contextRefreshed || listenerContainer.isAutoStartup()) {
listenerContainer.start();
}
}
所謂啟動(dòng)MessageListenerContainer其實(shí)就是調(diào)用MessageListenerContainer的start()方法。這也是SmartLifecycle的一個(gè)接口方法,它的實(shí)現(xiàn)必須保證調(diào)用了這個(gè)start()方法之后MessageListenerContainer將能夠接受到消息。
所以對(duì)@RabbitListener注解的整個(gè)處理流程就是這樣。
總結(jié)一下整個(gè)實(shí)現(xiàn)流程:
(1).@RabbitListener注解的方法所在的類首先是一個(gè)bean,因此,實(shí)現(xiàn)BeanPostProcessor接口對(duì)每一個(gè)初始化完成的bean進(jìn)行處理。
(2).遍歷bean中由用戶自己定義的所有的方法,找出其中添加了@RabbitListener注解的方法(也可以是@RabbitHandler注解,上面已經(jīng)講了,不再贅述)。
(3).讀取上面找出的所有方法上@RabbitListener注解中的值,并為每一個(gè)方法創(chuàng)建一個(gè)RabbitListenerEndpoint,保存在RabbitListenerEndpointRegistrar類中。
(4).在所有的bean都初始化完成,即所有@RabbitListener注解的方法都創(chuàng)建了endpoint之后,由我們配置的RabbitListenerContainerFactory將每個(gè)endpoint創(chuàng)建MessageListenerContainer。
(5).最后啟動(dòng)上面創(chuàng)建的MessageListenerContainer。
(6).至此,全部完成,MessageListenerContainer啟動(dòng)后將能夠接受到消息,再將消息交給它的MessageListener處理消息。
下面還剩下幾件事情才能真正實(shí)現(xiàn)上面的步驟:
(1).RabbitListenerContainerFactory只是個(gè)接口,它不會(huì)自己創(chuàng)建MessageListenerContainer,所以需要一個(gè)RabbitListenerContainerFactory實(shí)現(xiàn)類,它必須能創(chuàng)建MessageListenerContainer。
(2).MessageListenerContainer也只是一個(gè)接口,它不會(huì)自己接收消息,所以需要一個(gè)MessageListenerContainer實(shí)現(xiàn)類,它必須做到在啟動(dòng)后能夠接收消息,同時(shí)它必須能設(shè)置MessageListener,用以處理消息。
(3).MessageListener(或ChannelAwareMessageListener)也只是一個(gè)接口,所以還需要一個(gè)MessageListener實(shí)現(xiàn)類,它必須能調(diào)用我們加了@RabbitListener注解的方法。
4.2.2. SimpleRabbitListenerContainerFactory的實(shí)現(xiàn)
對(duì)應(yīng)上面的那三個(gè)步驟,看它是怎么實(shí)現(xiàn)的。
MessageListenerContainer的創(chuàng)建
首先看AbstractRabbitListenerContainerFactory抽象類的下面這個(gè)方法:
@Override
public C createListenerContainer(RabbitListenerEndpoint endpoint) {
C instance = createContainerInstance();
...
endpoint.setupListenerContainer(instance);
...
initializeContainer(instance, endpoint);
return instance;
}
注意里面兩個(gè)方法,后面這個(gè)方法里面SimpleRabbitListenerContainerFactory會(huì)做一些它獨(dú)有的屬性設(shè)置,前一個(gè)方法執(zhí)行結(jié)束,MessageListener就設(shè)置到MessageListenerContainer里面去了,可以跟蹤這個(gè)方法,一直到AbstractRabbitListenerEndpoint類的下面這個(gè)方法:
private void setupMessageListener(MessageListenerContainer container) {
MessageListener messageListener = createMessageListener(container);
Assert.state(messageListener != null, () -> "Endpoint [" + this + "] must provide a non null message listener");
container.setupMessageListener(messageListener);
}
可以看到在這個(gè)方法里創(chuàng)建了MessageListener,并將其設(shè)置到MessageListenerContainer里面去。
createMessageListener()方法有兩個(gè)實(shí)現(xiàn),實(shí)際調(diào)用的是MethodRabbitListenerEndpoint類里面的實(shí)現(xiàn):
@Override
protected MessagingMessageListenerAdapter createMessageListener(MessageListenerContainer container) {
...
MessagingMessageListenerAdapter messageListener = createMessageListenerInstance();
messageListener.setHandlerMethod(configureListenerAdapter(messageListener));
...
return messageListener;
}
看到setHandlerMethod(configureListenerAdapter(messageListener))這一行,這里創(chuàng)建并設(shè)置了一個(gè)HandlerAdapter,這個(gè)HandlerAdapter能夠調(diào)用我們加了@RabbitListener注解的方法。
SimpleMessageListenerContainer接收消息的實(shí)現(xiàn)
SimpleRabbitListenerContainerFactory創(chuàng)建的MessageListenerContainer是SimpleMessageListenerContainer類,下面看它是怎么在啟動(dòng)后就能接收消息的。
上面講過(guò)RabbitListenerEndpointRegistry類通過(guò)調(diào)用MessageListenerContainer的start()方法類啟動(dòng)這個(gè)MessageListenerContainer。
SimpleMessageListenerContainer類本身并沒(méi)有實(shí)現(xiàn)start()方法,在它繼承的抽象父類里面。進(jìn)入AbstractMessageListenerContainer抽象類找到start()方法的實(shí)現(xiàn)
@Override
public void start() {
if (isRunning()) {
return;
}
if (!this.initialized) {
synchronized (this.lifecycleMonitor) {
if (!this.initialized) {
afterPropertiesSet();
this.initialized = true;
}
}
}
try {
if (logger.isDebugEnabled()) {
logger.debug("Starting Rabbit listener container.");
}
configureAdminIfNeeded();
checkMismatchedQueues();
doStart();
}
catch (Exception ex) {
throw convertRabbitAccessException(ex);
}
}
真正的啟動(dòng)方法是doStart(),所以去SimpleMessageListenerContainer類中找這個(gè)類的doStart()實(shí)現(xiàn):
@Override
protected void doStart() throws Exception {
...
int newConsumers = initializeConsumers();
...
for (BlockingQueueConsumer consumer : this.consumers) {
AsyncMessageProcessingConsumer processor = new AsyncMessageProcessingConsumer(consumer);
processors.add(processor);
getTaskExecutor().execute(processor);
if (getApplicationEventPublisher() != null) {
getApplicationEventPublisher().publishEvent(new AsyncConsumerStartedEvent(this, consumer));
}
}
...
}
這個(gè)方法很長(zhǎng),細(xì)節(jié)就不去深究了,這里注意兩個(gè)方法,一個(gè)是initializeConsumers(),
protected int initializeConsumers() {
int count = 0;
synchronized (this.consumersMonitor) {
if (this.consumers == null) {
this.cancellationLock.reset();
this.consumers = new HashSet<BlockingQueueConsumer>(this.concurrentConsumers);
for (int i = 0; i < this.concurrentConsumers; i++) {
BlockingQueueConsumer consumer = createBlockingQueueConsumer();
this.consumers.add(consumer);
count++;
}
}
}
return count;
}
這個(gè)方法創(chuàng)建了BlockingQueueConsumer,數(shù)量等于concurrentConsumers參數(shù)的配置。
另一個(gè)方法是getTaskExecutor().execute(processor),前面用BlockingQueueConsumer創(chuàng)建了AsyncMessageProcessingConsumer(實(shí)現(xiàn)了Runnable接口),這里獲取到Executor來(lái)執(zhí)行,每一個(gè)MessageListenerContainer都有各自的Executor。
在AsyncMessageProcessingConsumer類的run()方法里面可以找到下面這段代碼:
while (isActive(this.consumer) || this.consumer.hasDelivery() || !this.consumer.cancelled()) {
try {
boolean receivedOk = receiveAndExecute(this.consumer); // At least one message received
if (SimpleMessageListenerContainer.this.maxConcurrentConsumers != null) {
if (receivedOk) {
if (isActive(this.consumer)) {
consecutiveIdles = 0;
if (consecutiveMessages++ > SimpleMessageListenerContainer.this.consecutiveActiveTrigger) {
considerAddingAConsumer();
consecutiveMessages = 0;
}
}
}
...
}
...
}
...
}
可以看到里面有個(gè)receiveAndExecute()方法,所以SimpleMessageListenerContainer接收消息的實(shí)現(xiàn)方案是:向Executor提交執(zhí)行Runnable,Runnable中循環(huán)接收消息。
MessageListener調(diào)用@RabbitListener注解方法處理消息的實(shí)現(xiàn)
上面的receiveAndExecute()方法接收消息的同時(shí)也將其處理了,繼續(xù)跟蹤,直到進(jìn)入下面這個(gè)方法:
protected void executeListener(Channel channel, Message messageIn) throws Exception {
...
invokeListener(channel, message);
...
}
在這個(gè)方法里面可以看到invokeListener()方法,
protected void invokeListener(Channel channel, Message message) throws Exception {
this.proxy.invokeListener(channel, message);
}
這里有個(gè)proxy,這個(gè)proxy是由下面這個(gè)方法創(chuàng)建的匿名類,
protected void actualInvokeListener(Channel channel, Message message) throws Exception {
Object listener = getMessageListener();
if (listener instanceof ChannelAwareMessageListener) {
doInvokeListener((ChannelAwareMessageListener) listener, channel, message);
}
else if (listener instanceof MessageListener) {
boolean bindChannel = isExposeListenerChannel() && isChannelLocallyTransacted();
if (bindChannel) {
RabbitResourceHolder resourceHolder = new RabbitResourceHolder(channel, false);
resourceHolder.setSynchronizedWithTransaction(true);
TransactionSynchronizationManager.bindResource(this.getConnectionFactory(),
resourceHolder);
}
try {
doInvokeListener((MessageListener) listener, message);
}
finally {
if (bindChannel) {
// unbind if we bound
TransactionSynchronizationManager.unbindResource(this.getConnectionFactory());
}
}
}
else if (listener != null) {
throw new FatalListenerExecutionException("Only MessageListener and SessionAwareMessageListener supported: "
+ listener);
}
else {
throw new FatalListenerExecutionException("No message listener specified - see property 'messageListener'");
}
}
這個(gè)方法里可以看到doInvokeListener()方法,已經(jīng)差不多接近我們的@RabbitListener注解的方法了,繼續(xù)跟蹤,
protected void doInvokeListener(ChannelAwareMessageListener listener, Channel channel, Message message)
throws Exception {
...
try {
listener.onMessage(message, channelToUse);
}
catch (Exception e) {
throw wrapToListenerExecutionFailedExceptionIfNeeded(e, message);
}
...
}
跟蹤listener.onMessage()方法,直到進(jìn)入MessagingMessageListenerAdapter類的onMessage()方法,
@Override
public void onMessage(org.springframework.amqp.core.Message amqpMessage, Channel channel) throws Exception {
Message<?> message = toMessagingMessage(amqpMessage);
if (logger.isDebugEnabled()) {
logger.debug("Processing [" + message + "]");
}
try {
Object result = invokeHandler(amqpMessage, channel, message);
if (result != null) {
handleResult(result, amqpMessage, channel, message);
}
else {
logger.trace("No result object given - no result to handle");
}
}
catch (ListenerExecutionFailedException e) {
if (this.errorHandler != null) {
try {
Object result = this.errorHandler.handleError(amqpMessage, message, e);
if (result != null) {
handleResult(result, amqpMessage, channel, message);
}
else {
logger.trace("Error handler returned no result");
}
}
catch (Exception ex) {
returnOrThrow(amqpMessage, channel, message, ex, ex);
}
}
else {
returnOrThrow(amqpMessage, channel, message, e.getCause(), e);
}
}
}
這里通過(guò)invokHandler()方法消費(fèi)獲取到的message,然后在catch里面處理異常,進(jìn)入invokeHandler()方法:
private Object invokeHandler(org.springframework.amqp.core.Message amqpMessage, Channel channel,
Message<?> message) {
try {
return this.handlerMethod.invoke(message, amqpMessage, channel);
}
catch (MessagingException ex) {
throw new ListenerExecutionFailedException(createMessagingErrorMessage("Listener method could not " +
"be invoked with the incoming message", message.getPayload()), ex, amqpMessage);
}
catch (Exception ex) {
throw new ListenerExecutionFailedException("Listener method '" +
this.handlerMethod.getMethodAsString(message.getPayload()) + "' threw exception", ex, amqpMessage);
}
}
在這里可以看到catch了所有的異常,也就是說(shuō)只要是我們消費(fèi)消息的方法里面拋出來(lái)的異常全都會(huì)被包裝成ListenerExecutionFailedException,并且這個(gè)Exception里面把消息也放進(jìn)去了。
這里的this.handlerMethod其實(shí)就是上面提到的HandlerAdapter,跟蹤它的invoke()方法,看它是怎么調(diào)用我們@RabbitListener注解的方法的。
最后我們跟蹤到InvocableHandlerMethod類的下面這個(gè)方法:
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
...
}
這里通過(guò)getBridgedMethod()方法拿到的就是@RabbitListener注解的方法了,這是在剛開(kāi)始處理@RabbitListener注解時(shí)就已經(jīng)保存下來(lái)的,然后就可以利用反射來(lái)調(diào)用這個(gè)方法,這樣就完成了接收并處理消息的整個(gè)流程。