Обновление контекста Spring при доставке сообщения JMS - PullRequest
2 голосов
/ 14 ноября 2011

Я хочу обновить контекст приложения, когда система получает сообщение JMS.Для этого я установил Spring Integration jms: message-driven-channel-adapter, который пересылает сообщение активатору службы, реализующему ApplicationContextAware.Этот активатор (класс ConfigurationReloader) вызывает метод ConfigurableApplicationContext # refresh ().

Ниже приведен фрагмент кода:

 <jms:message-driven-channel-adapter id="jmsDriverConfigurationAdapter"
    destination="configurationApplyQueue" channel="jmsConfigurationInboundChannel" />

 <channel id="jmsConfigurationInboundChannel"/>

 <service-activator input-channel="jmsConfigurationInboundChannel" ref="configurationReloader" method="refresh"/>

И мой активатор:

public final class ConfigurationReloader implements ApplicationContextAware {
        private ConfigurableApplicationContext applicationContext;

        public void refresh() {
           this.applicationContext.refresh();
        }

        @Override
        public void setApplicationContext(
                final ApplicationContext applicationContext) throws BeansException {
            if (applicationContext instanceof ConfigurableApplicationContext) {
                this.applicationContext =
                    (ConfigurableApplicationContext) applicationContext;
            }
        }
    }

В случаеДля доставки такого сообщения контекстная операция запуска завершается, но зависает при завершении работы bean-компонента DefaultMessageListenerContainer:

2011-11-14 15:42:52,980 [org.springframework.jms.listener.DefaultMessageLis tenerContainer#0-1] DEBUG org.springframework.jms.listener.DefaultMessageLis tenerContainer - Shutting down JMS listener container
2011-11-14 15:42:52,980 [org.springframework.jms.listener.DefaultMessageLis tenerContainer#0-1] DEBUG org.springframework.jms.listener.DefaultMessageLis tenerContainer - Waiting for shutdown of message listener invokers
2011-11-14 15:42:55,104 [org.springframework.jms.listener.DefaultMessageLis tenerContainer#0-1] DEBUG org.springframework.jms.listener.DefaultMessageLis tenerContainer - Still waiting for shutdown of 1 message listener invokers

Вызов этой операции через JMS крайне важен для меня, поскольку новые параметры конфигурации доставляются вместе с сообщением.Это стандартное приложение Spring MVC с DispatcherServlet на передней панели, основанное на последних версиях SpringCore и Spring Integration.Также я уверен, что это проблема, связанная с JMS, потому что вызов ConfigurationLoader через контроллер работает нормально.

После отладки он застревает после вызова строки DefaultMessageListenerContainer # 538 (метод wait () в lifecycleMonitor):

/**
 * Destroy the registered JMS Sessions and associated MessageConsumers.
 */
protected void doShutdown() throws JMSException {
    logger.debug("Waiting for shutdown of message listener invokers");
    try {
        synchronized (this.lifecycleMonitor) {
            while (this.activeInvokerCount > 0) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Still waiting for shutdown of " + this.activeInvokerCount +
                            " message listener invokers");
                }
                this.lifecycleMonitor.wait();   // <--- line 538
            }
        }
    }
    catch (InterruptedException ex) {
        // Re-interrupt current thread, to allow other threads to react.
        Thread.currentThread().interrupt();
    }
}

... на мониторе некому звонить notify / notifyAll, так что, может быть, это какая-то ошибка?

Спасибо за любые подсказки!

1 Ответ

2 голосов
/ 14 ноября 2011

Не могли бы вы объяснить, зачем вам такая сложная архитектура? Перезагрузить контекст приложения при получении сообщения JMS? Звучит безумно (или, может быть, гениально?)

Тем не менее, я не уверен на 100%, но предоставленная вами информация довольно ясна: вы пытаетесь закрыть контекст приложения во время использования сообщения JMS. Но поскольку потребитель управляется Spring, контекст не может быть уничтожен, поскольку он ожидает завершения всех bean-компонентов, включая ваш ConfigurationReloader, требуемый потребителем сообщений Spring Integration. И ConfigurationReloader не может завершиться, потому что он ожидает уничтожения контекста (refresh() блокирует).

Проще говоря - вы ввели циклическую зависимость и тупик.

Решение простое - отложить обновление контекста, чтобы оно произошло после потребления сообщения JMS. Самый простой способ будет:

public void refresh() {
    Thread destroyThread = new Thread() {
        @Override
        public void run() {
            this.applicationContext.refresh();
        }
    };
    destroyThread.start();
}

Не очень, но я почти уверен, что это сработает.

...