camel spring

by Shashank Sharma

通过Shashank Sharma

(How to configure multiple Camel Contexts in the Spring Boot application)

This article will assume you are already familiar with Apache Camel & Spring Boot, which their documentation describe as:

本文假定您已经熟悉Apache Camel和Spring Boot,其文档描述为:

Apache Camel is an open source framework for message-oriented middleware with a rule-based routing and mediation engine. It provides a Java object-based implementation of the Enterprise Integration Patterns using an application programming interface (or declarative Java domain-specific language) to configure routing and mediation rules.

Apache Camel面向消息的中间件的 开源 框架 ,具有基于规则的路由和中介引擎。 它使用应用程序编程接口 (或声明性的Java 域特定语言 )提供Java企业集成模式的实现,以配置路由和中介规则。

The domain-specific language means that Apache Camel can support type-safe smart completion of routing rules in an integrated development environment using regular Java code without large amounts of XML configuration files. Although XML configuration inside Spring Framework is also supported.

特定领域的语言意味着Apache Camel可以使用常规Java代码在集成开发环境中支持路由规则的类型安全的智能完成,而无需使用大量XML配置文件。 尽管也支持Spring Framework内部的XML配置。

Spring Boot is the starting point for building all Spring-based applications. Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring. Spring Boot makes it easy to create stand-alone, production-grade Spring-based Applications that you can run.

Spring Boot是构建所有基于Spring的应用程序的起点。 Spring Boot旨在通过最少的Spring前期配置使您尽快启动并运行。 Spring Boot使创建可运行的独立,生产级基于Spring的应用程序变得容易。

(The problem at hand)

You are designing a platform which enables end users to create multiple apps in your system. Each app can have it’s own Camel routes or can reuse predefined routes. The problem is how to ensure that one app Camel route doesn’t collide with other app routes.

您正在设计一个平台,使最终用户可以在系统中创建多个应用程序。 每个应用程序都可以拥有自己的骆驼路线,也可以重用预定义的路线。 问题是如何确保一个应用程序骆驼路线不会与其他应用程序路线冲突。

One way to solve this problem is to ensure routes are always uniquely named. But this is hard to enforce and even harder if end users can define their own routes. A neat solution is to create separate Camel Contexts for each app. It’s easier to manage. There are multiple articles on how to configure Apache Camel with Spring Boot application, but none on how to configure multiple Camel Contexts at runtime.

解决此问题的一种方法是确保路由始终被唯一命名。 但这很难执行,而且如果最终用户可以定义自己的路由,则更加困难。 巧妙的解决方案是为每个应用程序创建单独的Camel上下文。 更容易管理。 关于如何使用Spring Boot应用程序配置Apache Camel的文章 有多 ,但是关于如何在运行时配置多个Camel Context的文章却没有。

First exclude CamelAutoConfiguration from Spring Boot Application. Instead of CamelContext created by Spring Auto Configuration, we will create CamelContext as and when required.

首先从Spring Boot Application中排除CamelAutoConfiguration 。 取而代之的CamelContext创建由Spring自动配置,我们会在有需要时创建CamelContext。

@SpringBootApplication@EnableAutoConfiguration(exclude = {CamelAutoConfiguration.class})public class Application {
public static void main(String[] args) {    SpringApplication.run(Application.class, args);  }
}


To handle all Apache Camel configuration and to reuse the Spring properties, create CamelConfig Class.

要处理所有Apache Camel配置并重用Spring属性,请创建CamelConfig类。

@Configuration@EnableConfigurationProperties(CamelConfigurationProperties.class)@Import(TypeConversionConfiguration.class)public class CamelConfig {
@Autowired  private ApplicationContext applicationContext;
@Bean  @ConditionalOnMissingBean(RoutesCollector.class)  RoutesCollector routesCollector(ApplicationContext          applicationContext, CamelConfigurationProperties config) {
Collection<CamelContextConfiguration> configurations = applicationContext.getBeansOfType(CamelContextConfiguration.class).values();
return new RoutesCollector(applicationContext, new ArrayList<CamelContextConfiguration>(configurations), config);  }
/**  * Camel post processor - required to support Camel annotations.  */  @Bean  CamelBeanPostProcessor camelBeanPostProcessor(ApplicationContext applicationContext) {    CamelBeanPostProcessor processor = new CamelBeanPostProcessor();    processor.setApplicationContext(applicationContext);    return processor;  }
}


To create and manage CamelContext, create class CamelContextHandler.

要创建和管理CamelContext,请创建类CamelContextHandler

@Componentpublic class CamelContextHandler implements BeanFactoryAware {
private BeanFactory beanFactory;
@Autowired  private ApplicationContext applicationContext;
@Autowired  private CamelConfigurationProperties camelConfigurationProperties;
/*  * (non-Javadoc)  *  * @see  * org.springframework.beans.factory.BeanFactoryAware  * #setBeanFactory(org.springframework.beans.  * factory.BeanFactory)  */  @Override  public void setBeanFactory(BeanFactory beanFactory) {    this.beanFactory = beanFactory;  }
public boolean camelContextExist(int id) {    String name = "camelContext" + id;    return applicationContext.containsBean(name);  }
public CamelContext getCamelContext(int id) {    CamelContext camelContext = null;    String name = "camelContext" + id;    if (applicationContext.containsBean(name)) {           camelContext = applicationContext.getBean(name, SpringCamelContext.class);    } else {       camelContext = camelContext(name);    }    return camelContext;  }
private CamelContext camelContext(String contextName) {    CamelContext camelContext = new SpringCamelContext(applicationContext);    SpringCamelContext.setNoStart(true);    if (!camelConfigurationProperties.isJmxEnabled()) {      camelContext.disableJMX();    }
if (contextName != null) {      ((SpringCamelContext) camelContext).setName(contextName);    }
if (camelConfigurationProperties.getLogDebugMaxChars() > 0) {     camelContext.getProperties().put( Exchange.LOG_DEBUG_BODY_MAX_CHARS, "" + camelConfigurationProperties.getLogDebugMaxChars());
}
camelContext.setStreamCaching( camelConfigurationProperties.isStreamCaching());
camelContext.setTracing( camelConfigurationProperties.isTracing());
camelContext.setMessageHistory( camelConfigurationProperties.isMessageHistory());
camelContext.setHandleFault( camelConfigurationProperties.isHandleFault());
camelContext.setAutoStartup( camelConfigurationProperties.isAutoStartup());
camelContext.setAllowUseOriginalMessage(camelConfigurationProperties.isAllowUseOriginalMessage());
if (camelContext.getManagementStrategy().getManagementAgent() != null) {      camelContext.getManagementStrategy().getManagementAgent().setEndpointRuntimeStatisticsEnabled(camelConfigurationProperties.isEndpointRuntimeStatisticsEnabled());
camelContext.getManagementStrategy().getManagementAgent().setStatisticsLevel(camelConfigurationProperties.getJmxManagementStatisticsLevel());
camelContext.getManagementStrategy().getManagementAgent().setManagementNamePattern(camelConfigurationProperties.getJmxManagementNamePattern());
camelContext.getManagementStrategy().getManagementAgent().setCreateConnector(camelConfigurationProperties.isJmxCreateConnector());
}
ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;    configurableBeanFactory.registerSingleton(contextName, camelContext);
try {      camelContext.start();    } catch (Exception e) {      // Log error    }    return camelContext;  }
}
private BeanFactory beanFactory;


Now instead of autowiring CamelContext, autowire CamelContextHandler. CamelContextHandler#getCamelContext will return CamelContext based on its ID (where ID is the unique identifier of different apps). If there isn’t existing context for that ID, CamelContextHandler#getCamelContext will create CamelContext for that ID and return.

现在不是自动装配CamelContext,自动装配CamelContextHandler。 CamelContextHandler#getCamelContext将基于其ID(其中ID是不同应用程序的唯一标识符)返回CamelContext 。 如果该ID不存在上下文,则CamelContextHandler#getCamelContext将为该ID创建CamelContext并返回。

To prevent unnecessary creation of CamelContext, we can define a helper function in CamelContextHandler which can be called before calling getCamelContext to check if context exists for that ID.

为了防止不必要地创建CamelContext,我们可以在CamelContextHandler中定义一个辅助函数,可以在调用getCamelContext之前检查该辅助函数,以检查该ID是否存在上下文。

public boolean camelContextExist(int id) {  String name = "camelContext" + id;  return applicationContext.containsBean(name);}

You use the same way to load routes, and you will use CamelContextHandler#getCamelContext to get the context. Let’s assume your routes are stored in the database. And each of the routes are associated with some app ID. To load routes, we can define a method like:

您使用相同的方式加载路由,并将使用CamelContextHandler#getCamelContext获取上下文。 假设您的路线存储在数据库中。 并且每个路由都与某个应用程序ID相关联。 要加载路由,我们可以定义如下方法:

public void loadRoutes(String id) {  String routestr  = fetchFromDB(id);  if (routestr != null && !routestr.isEmpty()) {    try {      RoutesDefinition routes = camelContext.loadRoutesDefinition(IOUtils.toInputStream(routestr, "UTF-8"));
getCamelContext(id).addRouteDefinitions(routes.getRoutes());
} catch (Exception e) {      // Log error    }  }}

And to load routes at server startup which are already present in database we can use @PostConstruct annotation from Spring.

为了加载服务器启动时已经存在于数据库中的路由,我们可以使用Spring的@PostConstruct注释。

@PostConstructpublic void afterPropertiesSet() {  List<String> appIds = getAllEnabledApps();  appIds.forEach(id -> loadRoutes(id));}

As CamelContext objects are not created through Spring, Spring will not handle the lifecycle of these CamelContext beans. To stop all context when application stops, we can define closeContext method in the CamelConfig class to close all CamelContext gracefully.

由于CamelContext对象不是通过Spring创建的,因此Spring将不会处理这些CamelContext bean的生命周期。 要在应用程序停止时停止所有上下文,我们可以在CamelConfig类中定义closeContext方法以优雅地关闭所有CamelContext

@PreDestroyvoid closeContext() {  applicationContext.getBeansOfType(CamelContext.class).values() .forEach(camelContext -> {    try {      camelContext.stop();    } catch (Exception e) {      //Log error    }  });}

The above setup can help you run multiple Camel Contexts in a Spring Boot Application. If you have any questions or suggestions, feel free to write. Cheers.

上面的设置可以帮助您在Spring Boot应用程序中运行多个Camel Context。 如果您有任何疑问或建议,请随时写。 干杯。

Other articles by Shashank Sh.

Shashank Sh的其他文章。

翻译自: https://www.freecodecamp.org/news/configure-multiple-camel-context-in-spring-boot-application-d3a16396266/

camel spring