Я пытаюсь реализовать очередь для запуска заданий через Spring Batch. Очередь получает сообщения для заданий. Обрабатывает содержимое и запускает задание. Все работает так, как ожидалось, примерно в 50% случаев, и я не могу сказать, почему.
Вот код:
public class Listener implements MessageListener {
private static final Logger log = LoggerFactory.getLogger(Listener.class);
@Resource(name = "job")
Job job;
@Resource
JobLauncher jobLauncher;
/**
* Method called when message is sent to Queue. Reads messages in FIFO
* @param message Message pulled from Queue
*/
@Override
public void onMessage(Message message) {
log.info("Message received");
try {
String jobName = message.getJMSCorrelationID();
if (jobName.equals("job")) {
launchJob(message);
}
} catch (JMSException e) {
log.error("Error with queued message: " + message.toString());
}
Похоже, что иногда @Resource не инициализируются. Если я отлаживаю, я замечаю, что примерно в половине случаев они нулевые, а в другой половине времени они правильно подключены. Правильное сканирование закодировано в XML-файлах контекста.
Вот конфигурация очереди:
<!-- Embedded ActiveMQ Broker -->
<amq:broker id="broker" useJmx="false" persistent="false" >
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:0" />
</amq:transportConnectors>
</amq:broker>
<!-- ActiveMQ Destination -->
<amq:queue id="destination" physicalName="org" />
<!-- JMS ConnectionFactory to use, configuring the embedded broker using XML -->
<amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />
<!-- JMS Producer Configuration -->
<bean id="jmsProducerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
depends-on="broker"
p:targetConnectionFactory-ref="jmsFactory" />
<bean id="localQueueTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="jmsProducerConnectionFactory"
p:defaultDestination-ref="destination" />
<!--JMS Consumer Configuration-->
<bean id="jmsConsumerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
depends-on="broker"
p:targetConnectionFactory-ref="jmsFactory" />
<jms:listener-container container-type="default"
connection-factory="jmsConsumerConnectionFactory"
acknowledge="auto"
>
<jms:listener destination="org" ref="Queue" />
</jms:listener-container>
<bean id="Queue" class="org.Listener" />
Я нашел другие ТАК, что может быть так. По-видимому, существуют проблемы с созданием bean-компонентов в слушателях из-за различного образа жизни контекста bean-компонентов Listeners по сравнению со стандартными Spring Beans. См. здесь. Однако решения на самом деле нет. И единственное предложенное решение, которое я не могу реализовать, используя пространство имен jms:.
РЕДАКТИРОВАТЬ:
Я переместил некоторые контексты конфигурации. Я переместил Listener в его собственный файл контекста. Теперь @Resources инициализируются ровно один раз. Первое отправленное сообщение будет правильно запускать задание. Кажется, что каждое последующее сообщение имеет нулевую программу запуска и задание.
РЕДАКТИРОВАТЬ 2:
Я переместил конфигурацию очереди в контекстный файл за пределами общего. Кажется, это решило проблему.
Судя по отладчику, создается несколько экземпляров Listener. Некоторые правильно подключаются, а некоторые нет. Похоже, это связано с порядком создания экземпляров. Перемещение контекста, скорее всего, означает, что bean-компоненты доступны при создании прослушивателя.
Таким образом, кажется, что мне просто нужно добавить зависимость к компоненту Queue, чтобы он «зависел» от задания и средства запуска задания. Я попробую и, надеюсь, отчитаюсь.
РЕДАКТИРОВАТЬ 3:
Похоже, что "зависит от" не работает должным образом. Я выбрал решение перемещения логики очереди в другой контекст конфигурации. Этот контекст импортирует все ресурсы для задания. Каждый созданный объект (по какой-то причине их два) правильно подключен.
РЕДАКТИРОВАТЬ 4:
Проблема была вызвана многократными загрузками файла контекста. В качестве примера здесь была проблема, расположенная в файле web.xml.
<servlet>
<servlet-name>Job1 Controller</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>controller-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Job1 Controller</servlet-name>
<url-pattern>/Job1/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Job2 Controller</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>controller-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Job2 Controller</servlet-name>
<url-pattern>/Job2/</url-pattern>
</servlet-mapping>
DMLC
). каждое последующее сообщение... - невозможно - один и тот же экземпляр прослушивателя используется для всех сообщений, поэтому один из них подключен, он имеет одинаковые зависимости для каждого сообщения. Я предлагаю вам включить ведение журнала DEBUG дляorg.springframework
- он выдает обильные сообщения о проводке. - person Gary Russell   schedule 04.09.2014ContextLoadedListener
), а также в контексте сервлета. - person Gary Russell   schedule 04.09.2014