Я использую Apache Camel и Spring (не Spring Boot) с xml.
У меня есть файл конфигурации camel-context.xml с примером маршрута от сервера MQTT до JMSсервер и наоборот, просто для отправки сообщений.
Вот мой camel-context.xml:
<?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:util="http://www.springframework.org/schema/util"
xmlns:camel="http://camel.apache.org/schema/spring"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="quadtreeProcessor" class="es.gateway.router.QuadtreeProcessor" />
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<route id="quadTreeConsumerProducer">
<from uri="jms:topic:T_ETSI_PRODUCER"/>
<process ref="quadtreeProcessor"/>
<to uri="mqtt:quadtree?host=tcp://localhost:1883&publishTopicName=${header.publishTopicName}"/>
</route>
<route id="quadTreeConsumerRoute">
<from uri="mqtt:quadtree?host=tcp://localhost:1883&subscribeTopicName=CONSUMER/DENM/#"/>
<to uri="jms:topic:T_ETSI_CONSUMER"/>
</route>
</camelContext>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:10011"/>
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent" />
А вот мой Main.class:
package es.conncar.main;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.main.MainListener;
import org.apache.camel.main.MainListenerSupport;
import org.apache.camel.main.MainSupport;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import es.gateway.config.Config;
public class Main {
final static Logger logger = Logger.getLogger(Main.class);
private static boolean exit = false;
private org.apache.camel.spring.Main camelMain;
public static void main(String[] args) throws Exception {
try {
ApplicationContext springContext = new ClassPathXmlApplicationContext("app-context.xml");
logger.info("Spring context initialized");
Config config = (Config) springContext.getBean("config");
Main main = new Main();
main.boot();
} catch (Exception e) {
logger.error("Unknown error in main", e);
}
}
public void boot() throws Exception {
camelMain = new org.apache.camel.spring.Main();
camelMain.addMainListener((MainListener) new Events());
camelMain.setApplicationContextUri("camel-context.xml");
logger.info("Starting Camel. Use ctrl + c to terminate the JVM.\n");
camelMain.run();
}
public static class Events extends MainListenerSupport {
@Override
public void afterStart(MainSupport main) {
logger.info("Camel is now started!");
}
@Override
public void beforeStop(MainSupport main) {
logger.info("Camel is now being stopped!");
}
}
}
Проблема возникает при запуске одного и того же маршрута и конфигурации в моем главном классе, который умирает через несколько секунд из-за RuntimeCamelException .
Трассировка исключения:
Верблюды запускаются нормально
[30/11/2018 08:37:08][INFO ][es.gateway.main.Main] - Spring context initialized
[30/11/2018 08:37:08][INFO ][es.gateway.main.Main] - Starting Camel. Use ctrl + c to terminate the JVM.
Через 10 секунд
[30/11/2018 08:37:21][ERROR][es.gateway.main.Main] - Unknown error in Camel
org.apache.camel.RuntimeCamelException: java.util.concurrent.TimeoutException
at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1830)
at org.apache.camel.spring.SpringCamelContext.start(SpringCamelContext.java:136)
at org.apache.camel.spring.CamelContextFactoryBean.start(CamelContextFactoryBean.java:369)
at org.apache.camel.spring.CamelContextFactoryBean.onApplicationEvent(CamelContextFactoryBean.java:416)
at org.apache.camel.spring.CamelContextFactoryBean.onApplicationEvent(CamelContextFactoryBean.java:94)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at org.apache.camel.spring.Main.createDefaultApplicationContext(Main.java:222)
at org.apache.camel.spring.Main.doStart(Main.java:154)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.main.MainSupport.run(MainSupport.java:170)
at es.gateway.main.Main.boot(Main.java:105)
at es.gateway.main.Main.main(Main.java:77)
Caused by: java.util.concurrent.TimeoutException
at org.fusesource.mqtt.client.Promise.await(Promise.java:83)
at org.apache.camel.component.mqtt.MQTTEndpoint.connect(MQTTEndpoint.java:348)
at org.apache.camel.component.mqtt.MQTTConsumer.doStart(MQTTConsumer.java:38)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.startService(DefaultCamelContext.java:3705)
at org.apache.camel.impl.DefaultCamelContext.doStartOrResumeRouteConsumers(DefaultCamelContext.java:4023)
at org.apache.camel.impl.DefaultCamelContext.doStartRouteConsumers(DefaultCamelContext.java:3958)
at org.apache.camel.impl.DefaultCamelContext.safelyStartRouteServices(DefaultCamelContext.java:3878)
at org.apache.camel.impl.DefaultCamelContext.doStartOrResumeRoutes(DefaultCamelContext.java:3642)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:3494)
at org.apache.camel.impl.DefaultCamelContext.access$000(DefaultCamelContext.java:209)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:3253)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:3249)
at org.apache.camel.impl.DefaultCamelContext.doWithDefinedClassLoader(DefaultCamelContext.java:3272)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:3249)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:3165)
at org.apache.camel.spring.SpringCamelContext.start(SpringCamelContext.java:133)
... 18 more
Похоже, что маршрут выбрасывает тайм-аут, когда не удается подключиться к брокеру MQTT (это нормально) но это исключение встречается не в маршруте, а в контексте - Главный класс (это не нормально).
Я следовал этой кулинарной книге:
http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html
с JAR на верблюжьей пружине в классе org.apache.camel.spring.Main .
Я также проверил главу 13 в книге «Apache Camel in Action», но не нашел решения этой проблемы.Кажется, я отлично запускаю и настраиваю контекст верблюда.
У кого-нибудь есть такой опыт?Есть ли способ, чтобы маршруты работали, а основная программа работала, когда в маршрутах возникали исключения RuntimeExceptions?Я надеюсь на это!
Заранее спасибо!
РЕДАКТИРОВАТЬ: Я нашел несколько тем, говорящих об этом.Похоже, что решение заключается в активации Supervising Controller, но я не могу найти способ сделать это без Spring Boot (я использую обычный Spring со смешанным xml и конфигурацией аннотаций).Кто-нибудь может помочь?
Как запустить верблюда, даже если MQTT-сервер недоступен
Spring Context отключает верблюжьи маршруты при потере соединения activemq
EDIT2: я проверил, что проблема только с MQTT .Соединение JMS работает правильно и может продолжаться, даже если JMS-брокер не работает, и корректно обрабатывает повторные соединения, а соединение MQTT - нет.
EDIT3: Paho работает нормально, но обычное MQTT нет.Я тестировал тот же код с Paho в xml config (uri), и он ведет себя, как и ожидалось, аналогично JMS.Маршрут генерирует исключения, но продолжает идти, он не вызывает исключение для контекста, который вызывает остановку приложения.Может быть, мне не хватает опций в клиенте MQTT?