Эта статья является третьей в серии о Apache Camel и о том, как я использовал ее вместо IBM Message Broker для клиента. Этим летом я использовал Apache Camel несколько месяцев для создания ряда сервисов SOAP. Эти службы выполняли различные сторонние поиски данных для наших клиентов. Предыдущие статьи см. В части I: вдохновение и в части II: создание и тестирование маршрутов .
В конце июня я отправил электронное письмо инженерной команде моего клиента. Его тема: «Внешняя конфигурация и микросервисы». Я рекомендовал интегрировать Spring Boot в проект Apache Camel, над которым я работал. Я сказал им, что моей главной мотивацией была его внешняя конфигурация . Я также указал на функцию WAR без контейнера, в которой Tomcat (или Jetty) встроен в WAR, и вы можете запустить свое приложение с помощью «java -jar appname.war». Я упомянул микросервисы и то, что Spring Boot облегчит разделение проекта на структуру проекта для службы, если мы захотим пойти по этому пути. Затем я задал два простых вопроса:
- Можно ли интегрировать Spring Boot?
- Должен ли я разделить проект на микросервисы?
Оба эти предложения были хорошо приняты, поэтому я пошел на работу.
Весна 4
До того, как я интегрировал Spring Boot, я знал, что мне нужно перейти на Spring 4 . Версия Camel, которую я использовал (2.13.1), не поддерживала Spring 4. Я обнаружил проблему CAMEL-7074 (Support spring 4.x) и добавил комментарий, чтобы увидеть, когда она будет исправлена. После работы с зависимостями и попытки использования Camel 2.14-SNAPSHOT я смог обновить CXF 3.0. Однако это не решило мою проблему. Были некоторые несовместимые изменения API между Spring 3.3.x и Spring 4.0.x, и модуль camel-test-spring не будет работать с обоими. Я предложил следующее:
Я думаю, что самый простой путь вперед — это создать два модуля: camel-test-spring и camel-test-spring3. Первый компилируется против Spring 4, а второй — против Spring 3. Вы можете переключить его так, чтобы по умолчанию camel-test-spring перешел на Spring 3, но camel-test-spring4, кажется, не смотрит вперед, как вы, надеюсь, не сделаете нужен верблюд-тест-весна5.
Я сделал это изменение в вилке, и это работает в моем проекте. Я могу обновиться до Camel 2.14-SNAPSHOT и CXF 3.0 с Spring 3.2.8 (используя camel-test-spring3). Я также могу перейти на Spring 4, если использую обновленную тестовую верблюжью пружину.
Вот запрос на удаление, который имеет это изменение: https://github.com/apache/camel/pull/199
Команда Camel объединила мои предложенные изменения пару недель спустя. К сожалению, похожая ситуация произошла с Spring 4.1 , поэтому вам придется ждать Camel 2.15, если вы хотите использовать Spring 4.1.
Сделав исправленную версию 2.14-SNAPSHOT доступной для моего проекта, я смог обновить ее до Spring 4 и CXF 3 с небольшими изменениями в моем pom.xml.
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> - <camel.version>2.13.1</camel.version> - <cxf.version>2.7.11</cxf.version> - <spring.version>3.2.8.RELEASE</spring.version> + <camel.version>2.14-SNAPSHOT</camel.version> + <cxf.version>3.0.0</cxf.version> + <spring.version>4.0.5.RELEASE</spring.version> </properties> ... + <!-- upgrade camel-spring dependencies --> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aop</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-tx</artifactId> + <version>${spring.version}</version> + </dependency>
Мне также пришлось изменить некоторые импорты для CXF 3.0, поскольку он включает новую основную версию Apache WSS4J (2.0.0) .
-import org.apache.ws.security.handler.WSHandlerConstants; +import org.apache.wss4j.dom.handler.WSHandlerConstants; ... -import org.apache.ws.security.WSPasswordCallback; +import org.apache.wss4j.common.ext.WSPasswordCallback;
После того, как все было обновлено, я продолжил разработку сервисов в течение следующих нескольких недель.
Весенний ботинок
В конце июля я интегрировал Spring Boot. Это было довольно просто и в основном состояло из добавления / удаления зависимостей и удаления версий, уже определенных в начальной загрузке Boot.
+ <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>1.1.4.RELEASE</version> + </parent> ... <cxf.version>3.0.1</cxf.version> + <java.version>1.7</java.version> + <servlet-api.version>3.1.0</servlet-api.version> <spring.version>4.0.6.RELEASE</spring.version> ... - <artifactId>maven-compiler-plugin</artifactId> - <version>2.5.1</version> - <configuration> - <source>1.7</source> - <target>1.7</target> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> </plugin> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + </plugin> </plugins> </build> <dependencies> + <!-- spring boot --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + <exclusions> + <exclusion> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-log4j</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-tomcat</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> <!-- camel --> ... - <!-- upgrade camel-spring dependencies --> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-context</artifactId> - <version>${spring.version}</version> - </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-aop</artifactId> - <version>${spring.version}</version> - </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-tx</artifactId> - <version>${spring.version}</version> - </dependency> ... - <!-- logging --> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.6</version> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-log4j12</artifactId> - <version>1.7.6</version> - </dependency> - <dependency> - <groupId>log4j</groupId> - <artifactId>log4j</artifactId> - <version>1.2.17</version> - </dependency> - <!-- utilities --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> - <version>2.3</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> - <version>1.4</version> ... <!-- testing --> <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <exclusions> + <exclusion> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-test</artifactId> - <version>${spring.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>1.9.5</version> - <scope>test</scope> - </dependency>
Затем я удалил AppInitializer.java
класс, упомянутый во второй части, и добавил Application.java
класс.
@Configuration @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }) @ComponentScan public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } @Bean public ServletRegistrationBean servletRegistrationBean() { CXFServlet servlet = new CXFServlet(); return new ServletRegistrationBean(servlet, "/api/*"); } @Bean public EmbeddedServletContainerCustomizer containerCustomizer() { return new EmbeddedServletContainerCustomizer() { @Override public void customize(ConfigurableEmbeddedServletContainer container) { ErrorPage error401Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/401.html"); ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html"); ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.html"); container.addErrorPages(error401Page, error404Page, error500Page); } }; } }
Страницы ошибок, которые вы видите сконфигурированными выше, были настроены и скопированы с пользовательских страниц ошибок Тима Спорчича с Spring Boot .
Динамические источники данных
Я исключил связанные с DataSource классы автоконфигурации, потому что у этого приложения было много источников данных. Также требовалось разрешить добавление источников данных на лету простым редактированием application.properties. Я спросил, как это сделать в Stack Overflow, и получил отличный ответ от Стефана Николла .
Проблемы с весенней загрузкой
Я столкнулся с парой проблем после интеграции Spring Boot. Во-первых, он удалял заголовки content- * для ответов CXF . Это произошло только при запуске WAR в Tomcat, и я смог найти обходной путь с помощью настраиваемого ResponseWrapper и Filter. Эта проблема была исправлена в Spring Boot 1.1.6.
Другая проблема заключалась в том, что функция переопределения свойств не работала при установке переменных среды. setenv.sh
Обходным решением было создать скрипт в $ CATALINA_HOME / bin и добавить туда переменные окружения. См. Раздел 3.4 в RUNNING.txt Tomcat 7 для получения дополнительной информации.
Неисправности SOAP
После обновления до Spring 4 и интеграции Spring Boot я продолжил миграцию потоков IBM Message Broker. Моей целью было сделать все новые сервисы обратно совместимыми, но я столкнулся с проблемой. С новыми сервисами ошибки SOAP отправлялись обратно клиенту вместо сообщений об ошибках в сообщении SOAP. Я предложил исправить это одним из двух способов:
- Измените клиент так, чтобы он смотрел на ошибки SOAP и обрабатывал их соответствующим образом.
- Измените новые службы, чтобы сообщения возвращались вместо сбоев.
Для # 2 я узнал, как преобразовывать сообщения об ошибках в список рассылки пользователей Camel. Однако команда решила улучшить клиента, и вместо этого мы добавили обработку ошибок.
Микросервис Развертывание
Когда я впервые интегрировал Spring Boot, я планировал разделить наш проект на проект за услугу. Это позволило бы каждой службе развиваться самостоятельно, вместо монолитной войны, которая содержит все службы. В групповых обсуждениях была некоторая обеспокоенность по поводу нехватки памяти при запуске нескольких экземпляров вместо одного.
Я указал на интересную ветку в списке рассылки Camel о развертывании маршрутов с маршрутом-на-jvm или всеми в одной и той же JVM. Рекомендация этого потока состояла в том, чтобы объединить похожие маршруты, если вы хотите их разделить.
В конце концов, мы решили позволить нашей операционной команде решить, как они хотят управлять / развертывать все. Я упоминал, что Spring Boot может работать с Tomcat, Jetty, JBoss и даже облачными провайдерами, такими как Heroku и Cloud Foundry . Я подсчитал, что разделение проекта займет меньше дня, как и превращение его в монолитную ВОЙНУ.
Резюме
В этой статье объясняется, как мы обновили наше приложение Apache Camel до Spring 4 и интегрировали Spring Boot. Было немного трудно заставить вещи работать, но ничего, что не могли исправить несколько запросов и обходных путей. Мы обнаружили некоторые проблемы с настройкой переменных среды для Tomcat и решили не разбивать наш проект на небольшие микросервисы. Надеемся, что эта статья поможет людям, пытающимся установить Camelize в Spring Boot .
В следующей статье я расскажу о нагрузочном тестировании с Gatling , регистрации в Log4j2 и мониторинге с помощью hawtio и New Relic .