Как настроить несколько контекстов Camel в программе Spring Boot

1656685087 kak nastroit neskolko kontekstov camel v programme spring boot

автор Шашанк Шарма

gmbVrFLJunInNfmAqchAyPBNPSBRr7zBft0N

В этой статье предполагается, что вы уже знакомы с Apache Camel & Spring Boot, которые в их документации описываются как:

Apache Camel это платформа с открытым исходным кодом для промежуточного программного обеспечения, ориентированного на сообщение, с механизмом маршрутизации и посредничества на основе правил. Он обеспечивает реализацию корпоративных интеграционных шаблонов на основе объектов Java, используя интерфейс прикладного программирования (или декларативный язык Java для домена) для настройки правил маршрутизации и посредничества.

Доменно-специальный язык означает, что Apache Camel может поддерживать безопасное для типов интеллектуальное завершение правил маршрутизации в интегрированной разработке с использованием обычного кода Java без большого количества файлов конфигурации XML. Хотя конфигурация XML в Spring Framework также поддерживается.

Весенний ботинок является отправной точкой для создания всех приложений на основе Spring. Spring Boot создан для того, чтобы поскорее начать работу с минимальной предварительной конфигурацией Spring. Spring Boot позволяет легко создавать автономные приложения на базе Spring производительного класса, которые можно запускать.

Проблема под рукой

Вы разрабатываете платформу, позволяющую конечным пользователям создавать несколько программ в вашей системе. Каждое приложение может иметь собственные маршруты Camel или повторно использовать предварительно определенные маршруты. Проблема состоит в том, как обеспечить, чтобы один маршрут Camel приложения не сталкивался с маршрутами других приложений.

Один из способов решения этой проблемы состоит в том, чтобы маршруты всегда имели уникальные названия. Но это трудно обеспечить и еще труднее, если конечные пользователи могут определять собственные маршруты. Прекрасным решением является создание отдельных контекстов Camel для каждой программы. Легче управлять. Есть несколько статей о том, как настроить Apache Camel с помощью программы Spring Boot, но нет ни одной о том, как настроить несколько контекстов Camel во время выполнения.

Сначала исключить CamelAutoConfiguration из программы Spring Boot. Вместо этого CamelContext созданный Spring Auto Configuration, мы создадим CamelContext как и когда нужно.

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

Чтобы обработать всю конфигурацию 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;  }
}

Создавать и управлять 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;  }
}

Теперь вместо автопроводки CamelContextавтопровод CamelContextHandler. CamelContextHandler#getCamelContext вернется CamelContext на основе его идентификатора (где ID – это уникальный идентификатор разных программ). Если для этого идентификатора нет контекста, CamelContextHandler#getCamelContext создаст CamelContext для этого идентификатор и возврат.

Чтобы предотвратить ненужное создание CamelContext, мы можем определить вспомогательную функцию в CamelContextHandler который можно вызвать перед вызовом getCamelContext чтобы проверить, существует ли контекст для этого идентификатора.

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

Вы используете тот же способ для загрузки маршрутов, и вы будете использовать CamelContextHandler#getCamelContext чтобы получить контекст. Предположим, что ваши маршруты хранятся в базе данных. И каждый из маршрутов связан с определенным идентификатором программы. Чтобы скачать маршруты, мы можем определить следующий метод:

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    }  }}

А для загрузки маршрутов при запуске сервера, уже присутствующих в базе данных, мы можем использовать аннотацию @PostConstruct из Spring.

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

как CamelContext объекты не создаются через Spring, Spring не будет обрабатывать их жизненный цикл CamelContext фасоль. Чтобы остановить весь контекст, когда программа останавливается, мы можем определить closeContext метод в CamelConfig класс, чтобы закрыть все CamelContext изящно.

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

Вышеуказанная настройка может помочь вам запустить несколько контекстов Camel в загрузочной программе Spring. Если у вас есть вопросы или предложения, пишите. Ура.

Другие статьи Шашенко Ш.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *