Spring整合rabbitmq實(shí)踐(三):源碼

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è)流程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,238評(píng)論 3 428
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,823評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,604評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,339評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,713評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評(píng)論 3 445
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,893評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,448評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,201評(píng)論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,397評(píng)論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,631評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,033評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,321評(píng)論 1 293
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,128評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,347評(píng)論 2 377

推薦閱讀更多精彩內(nèi)容

  • 人生總有幾個(gè)重要時(shí)刻是在一個(gè)個(gè)再普通不過(guò)的日子里來(lái)臨的,也許一念之間你的人生將會(huì)被改寫(xiě)。 昨天又看到一則新聞,福建...
    太平洋里的貓閱讀 141評(píng)論 0 2
  • 1.gethostbyname() 返回主機(jī)名對(duì)應(yīng)的 IPv4地址
    雨y飄零久閱讀 174評(píng)論 0 0
  • 生活本身就是煎熬。我不是想表達(dá)悲觀的情緒,是覺(jué)得感同身受,如果這么容易,奮斗的堅(jiān)持沒(méi)有了存在,多可惜。 漫長(zhǎng)的炎炎...
    嗷大喵愛(ài)吃饅頭閱讀 166評(píng)論 0 0
  • 青蔥歲月, 跌跌撞撞, 由懵懂開(kāi)始漸漸想要成熟, 由空白開(kāi)始漸漸編織夢(mèng)想, 青春五味雜陳, 我們品盡酸甜苦辣, 我...
    白駒過(guò)隙的美妙閱讀 336評(píng)論 0 0
  • 風(fēng)一來(lái) 我,也成了一片葉子 醉倒在樹(shù)枝間 突然把你想起 想你是風(fēng)吹落葉 沒(méi)有歸期
    斯人獨(dú)往閱讀 366評(píng)論 3 6