вторник, января 12, 2016

Best practices ServiceMix and Apache Camel

В этой статье я решил поделится всеми своими рекомендациями при разработке с применением ServiceMix и Apache Camel. По мере развития статья будет дополняться.
  • Используйте Spring DSL вместо Java DSL. Это позволит в некоторых случаях при необходимости вести разработку в обычном текстовом редакторе, избавит вас от format-hell. Так же в силу древовидности XML вам не придется использовать костыли по типу end(), которые вы вынуждены вставлять чтобы контролировать блоки кода.
  • При подключении к ActiveMQ всегда используйте failover (failover:tcp://127.0.0.1:61616)
  • При использовании файлового адаптера читающего файлы из директории, всегда подключайте фильтр на проверку пустого файла.
    import org.apache.camel.component.file.GenericFile;
    import org.apache.camel.component.file.GenericFileFilter;
    import org.apache.log4j.Logger;
    
    public class EmptyFilter<T> implements GenericFileFilter<T> {
     private static Logger log = Logger.getLogger(EmptyFilter.class);
    
     public boolean accept(GenericFile<T> file) {
      boolean res = false;
      if (!file.isDirectory()) {
       if (file.getFileLength() > 0) {
        res = true;
       }
      }
      return res;
     }
    }
    
    
    Иcпользование:
    file:{{inbox}}?filter=#emptyFilter
    
    
  • Итерирование по коллекциям удобно делать через http://camel.apache.org/splitter.html из коробки предоставляющий возможность параллелизации
    <split parallelProcessing="true">
     <xpath>/items/*</xpath>
            <to uri="direct:foo" />
    </split>
  • Все используемые библиотеке выносите в отдельный файл feature. И никогда не носите библиотеки внутри разрабатываемых вами bundle. Любой jar можно установить используя wrap.
    <?xml version="1.0" encoding="UTF-8"?>
    <features>
      <feature name='tir_config' version='1.0' install='auto'>
        <feature version="3.2.11.RELEASE_1">spring-jdbc</feature>
        <feature>jdbc</feature>
        <feature>jetty</feature>
        <feature>camel-quartz</feature>
        <feature>activemq-broker</feature>
        <feature>camel-jetty</feature>
        <feature>camel-jackson</feature>
        <feature>camel-urlrewrite</feature>
        <feature>camel-saxon</feature>
        <feature>activemq-web-console</feature>
        <bundle>wrap:mvn:org.apache.httpcomponents/httpcore/4.3.3</bundle>
        <bundle>wrap:mvn:org.apache.httpcomponents/httpclient/4.3.6</bundle>
        <bundle>wrap:mvn:org.apache.commons/commons-pool2/2.4.2</bundle>
        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jedis/2.7.3_1</bundle>
      </feature>
    </features>
    
  • JDBC-источники данных(DataSource) удобно деплоить как blueprint и не городить отдельный bundle, который будет доступен как osgi-сервис. Также всегда добавляйте свойство osgi.jndi.service.name, это позволит обращаться к источнику также через JNDI. Файл достаточно положить в папку deploy. Это представляет настройки в чистом виде, без необходимости выводить их в отдельный настроечный файл
    <?xml version="1.0" encoding="UTF-8"?>
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0">
     <bean id="postgresPoolingDS" class="org.apache.commons.dbcp.BasicDataSource">
      <property name="driverClassName" value="org.postgresql.Driver" />
      <property name="url" value="jdbc:postgresql://10.1.6.66/postgres" />
      <property name="username" value="postgres" />
      <property name="password" value="postgres" />
      <property name="defaultAutoCommit" value="true" />
      <property name="testWhileIdle" value="false" />
      <property name="testOnBorrow" value="false" />
      <property name="testOnReturn" value="false" />
      <property name="timeBetweenEvictionRunsMillis" value="5000" />
      <property name="maxActive" value="10" />
      <property name="maxIdle" value="10" />
      <property name="minIdle" value="0" />
      <property name="maxWait" value="10000" />
      <property name="initialSize" value="1" />
      <property name="removeAbandonedTimeout" value="10" />
      <property name="removeAbandoned" value="true" />
      <property name="logAbandoned" value="false" />
      <property name="minEvictableIdleTimeMillis" value="30000" />
     </bean>
     <service interface="javax.sql.DataSource" ref="postgresPoolingDS" >
      <service-properties>
       <entry key="datasource.name" value="postgres" />
       <entry key="osgi.jndi.service.name" value="jdbc/postgresds" />
      </service-properties>
     </service>
    </blueprint>
  • Связи между модулями реализуйте через osgi-сервисы. Зависимостями можно управлять через настроечные файлы. Таким образом можно например настраивать используемый источник данных (DataSource)
    <osgi:reference id="dataSource" interface="javax.sql.DataSource" filter="(datasource.name=${dbType})" />
    Использование osgi-сервисов избавит вас от головной боли связанной с очередностью запуска модулей. Они сами будут разруливать свои зависимости, и ждать нужного osgi-сервиса(Модуль будет находиться в состоянии WAIT). В отличии от использования кода напрямую, когда модуль просто свалится (FAIL), и даже появление нужной зависимости не заставит его подняться. Необходимо будет делать restart вручную. Если какая-то часть кода просится в библиотеку, выносите его в отдельный jar и подключайте в файле features, про который мы уже сказали выше.

Комментариев нет: