如何让Spring Boot集成Camel应用在from端点不可用时正常启动?
问题背景
基于Spring Boot的Apache Camel应用需要提升容错能力:当MQ、SMPP等from端点不可用时,应用仍能正常启动,且定期重试连接,待端点恢复后自动接收消息。当前代码在SMPP端点不可用时会直接启动失败。
当前代码
// Application.java @SpringBootApplication @ConfigurationPropertiesScan public class Application { @Autowired private CamelContext context; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean CommandLineRunner init(ProducerTemplate template) { return args -> { context.addRoutes(new MQRouteBuilder()); context.addRoutes(new SMPPRouteBuilder()); }; } } // SMPPRouteBuilder.java public class SMPPRouteBuilder extends RouteBuilder { public void configure() throws Exception { from("smpp://{{camel.component.smpp.configuration.host}}").to("direct:processSMS"); //... } }
启动报错
java.lang.IllegalStateException: Failed to execute CommandLineRunner at
org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:787)
~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
...
Caused by: java.net.UnknownHostException: localhostInvalid
...
解决方案
通过配置Camel允许启动失败+自定义路由重试策略实现需求:
1. 配置Camel允许路由启动失败
添加CamelContextConfiguration,让Camel在部分路由启动失败时不终止整个应用:
@Bean CamelContextConfiguration camelContextConfiguration() { return context -> { // 允许单个路由启动失败,不影响应用启动 context.setAllowStartupFailures(true); }; }
2. 自定义路由重试策略
创建AutoRetryRoutePolicy,在路由启动失败后定期重试启动:
@Component public class AutoRetryRoutePolicy implements RoutePolicy { private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); // 重试间隔,单位毫秒,可配置到application.properties private static final long RETRY_DELAY = 30000; @Override public void onStartupFailure(Route route, Throwable cause) { // 路由启动失败,安排下一次重试 scheduler.schedule(() -> attemptRestart(route), RETRY_DELAY, TimeUnit.MILLISECONDS); } private void attemptRestart(Route route) { try { CamelContext context = route.getRouteContext().getCamelContext(); RouteStatus status = context.getRouteStatus(route.getId()); // 仅当路由未启动时尝试重启 if (!status.isStarted()) { context.startRoute(route.getId()); } } catch (Exception e) { // 重试失败,继续安排下一次重试 scheduler.schedule(() -> attemptRestart(route), RETRY_DELAY, TimeUnit.MILLISECONDS); } } @Override public void onRemove(Route route) { // 路由移除时关闭调度器 scheduler.shutdown(); } // 实现其他空方法 @Override public void onInit(Route route) {} @Override public void onStart(Route route) {} @Override public void onStop(Route route) {} @Override public void onSuspend(Route route) {} @Override public void onResume(Route route) {} }
3. 给目标路由绑定重试策略
修改SMPPRouteBuilder,将重试策略绑定到SMPP路由上:
public class SMPPRouteBuilder extends RouteBuilder { @Autowired private AutoRetryRoutePolicy autoRetryRoutePolicy; @Override public void configure() throws Exception { from("smpp://{{camel.component.smpp.configuration.host}}") .routeId("smppRoute") .routePolicy(autoRetryRoutePolicy) // 绑定重试策略 .to("direct:processSMS"); } }
效果说明
- 应用启动时,即使SMPP端点不可用,也能正常启动,MQ路由会正常监听消息
- SMPP路由启动失败后,会每隔30秒自动重试连接,直到端点恢复可用,自动开始接收消息
内容的提问来源于stack exchange,提问作者simonalexander2005
相关产品推荐
相关产品推荐

