Статьи

Верблюд: создать приложение на основе сообщений

Это длинная статья, которая содержит три отдельные темы:

  • Начало работы с Apache Camel с Java
  • Улучшение запуска маршрутов с помощью CamelRunner
  • Создание приложения на основе сообщений с использованием Camel

Но так как я подготовил camel-demo-1.0.0-SNAPSHOT-project.zip , в который включены все эти материалы, я подумал, что будет проще объединить их и представить в целом.

Начало работы с Apache Camel с Java

Испытать Camel с несколькими строками Groovy — это одно, а получить полноценный проект на Java — другое дело. Сегодня я покажу вам, как начать работу над Apache Camel с проектом на основе Maven . Вы также можете использовать предоставленную camel-demo качестве шаблона проекта, чтобы начать свой собственный проект Apache Camel. Вам просто нужно переименовать пакет Java и переименовать группу pom и идентификаторы артефактов в соответствии с вашими потребностями.

Подготовка Maven-проекта с зависимостями Camel

Разархивируйте исходный код проекта camel-demo , и вы увидите базовый макет каталога.

1
2
3
4
5
6
7
camel-demo
    +- bin
    +- config
    +- data
    +- src
    +- pom.xml
    +- README.txt

Что делает эту демонстрацию проектом на основе Camel, так это просто объявление в pom.xml . Давайте посмотрим файл и его зависимости.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<?xml version='1.0' encoding='UTF-8'?>
 
    <modelVersion>4.0.0</modelVersion>
    <groupId>deng.cameldemo</groupId>
    <artifactId>camel-demo</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <slf4j.version>1.6.6</slf4j.version>
        <camel.version>2.10.1</camel.version>
    </properties>
 
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>project</descriptorRef>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
 
        <!-- Unit testing lib -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit-dep</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-library</artifactId>
            <version>1.2.1</version>
            <scope>test</scope>
        </dependency>
 
        <!-- Logging lib -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
 
        <!-- Apache Commons lib -->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.0.1</version>
        </dependency>
 
        <!-- Apache Camel -->
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-core</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-groovy</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-jackson</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-mina</artifactId>
            <version>${camel.version}</version>
        </dependency>
 
    </dependencies>
 
</project>

Этот pom.xml декаляризирует приложение на основе Java, и он создаст jar . Требуется минимум JDK 6 или выше. Помимо типичного junit и hamcrest для модульного тестирования, я также добавил slf4j для ведения журнала. Я также добавил в проект пару Apache’s commons-lang/io . Я думаю, что это основные настройки, которые должно использовать любое приложение на основе Java.

maven-assembly-plugin я объявил, предназначен только для этой цели, и вы можете изменить или удалить его, чтобы удовлетворить потребности вашего проекта.

Для верблюжьих зависимостей вам потребуется минимальное camel-core для построения маршрутов. И тогда вы можете добавить любые дополнительные компоненты, которые вы планируете использовать в своем проекте. Я добавил следующее для построения типичной разработки приложений на основе сообщений:

  1. camel-spring — мы хотим иметь возможность объявить маршруты Camel в XML-файлах как конфигурацию. Смотрите каталог camel-demo/config для примеров.
  2. camel-jackson — мы хотим обрабатывать данные сообщений в нашем приложении в формате JSON.
  3. camel-mina — мы хотим отправлять данные сообщений по сети через TCP-сокет.
  4. camel-groovy — [необязательно], мы хотим иметь возможность добавлять динамические сценарии в маршрут даже внутри конфигурации xml. Это отлично подходит для отладки и POC.

Обратите внимание, что поскольку мы используем несколько зависимостей компонентов верблюда, я решил установить свойство Maven ${camel.version} чтобы при обновлении Camel было проще поддерживать файл pom.xml в одном месте.

Вы должны иметь возможность перейти в каталог проекта и запустить mvn compile чтобы убедиться, что проект. Должен компилироваться без ошибок.

Улучшение запуска маршрутов с помощью CamelRunner

pom.xml файл проекта pom.xml , вы можете приступить к созданию маршрутов Camel для обработки собственной бизнес-логики. Прежде чем мы будем слишком взволнованы, давайте попробуем простой HelloRoute чтобы увидеть, как он работает и как мы можем запустить его в первую очередь. Вот код определения маршрута в src/main/java/deng/cameldemo/HelloRoute.java .

01
02
03
04
05
06
07
08
09
10
11
package deng.cameldemo;
 
import org.apache.camel.builder.RouteBuilder;
 
public class HelloRoute extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        from('timer://helloTimer?period=3000').
            to('log:' + getClass().getName());
    }
}


Проведи пробную поездку на верблюде

Чтобы увидеть выше в действии, нам нужно добавить его в CamelContext и запустить контекст. Для автономной программы на Java мы бы написали этот установочный код в Main классе. На самом деле Camel поставляется с абстрактным классом org.apache.camel.main.MainSupport который вы можете использовать для расширения своего собственного Main . Тем не менее, я думаю, что было бы еще лучше, если бы Camel предоставил CamelRunner который может работать так.

1
$ java CamelRunner deng.cameldemo.HelloRoute

Такой CamelRunner был бы очень CamelRunner для пользователя и CamelRunner для повторного использования, так что я так и сделал. Я написал один такой:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package deng.cameldemo;
 
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
/**
 * A main program to start Camel and run as a server using RouteBuilder class names or
 * Spring config files.
 *
 * <p>Usage:
 *
 * java deng.cameldemo.CamelRunner deng.cameldemo.HelloRoute
 *
 * or
 *
 * java -Dspring=true deng.cameldemo.CamelRunner /path/to/camel-spring.xml
 *
 * @author Zemian Deng
 */
public class CamelRunner {
    public static void main(String[] args) throws Exception {
        CamelRunner runner = new CamelRunner();
        runner.run(args);
    }
 
    private static Logger logger = LoggerFactory.getLogger(CamelRunner.class);
    public void run(String[] args) throws Exception {
        if (Boolean.parseBoolean(System.getProperty('spring', 'false')))
            runWithSpringConfig(args);
        else
            runWithCamelRoutes(args);
 
        // Wait for user to hit CRTL+C to stop the service
        synchronized(this) {
            this.wait();
        }
    }
 
    private void runWithSpringConfig(String[] args) {
        final ConfigurableApplicationContext springContext = new FileSystemXmlApplicationContext(args);
 
        // Register proper shutdown.
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    springContext.close();
                    logger.info('Spring stopped.');
                } catch (Exception e) {
                    logger.error('Failed to stop Spring.', e);
                }
            }
        });
 
        // Start spring
        logger.info('Spring started.');
    }
 
    private void runWithCamelRoutes(String[] args) throws Exception {
        final CamelContext camelContext = new DefaultCamelContext();       
        // Register proper shutdown.
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    camelContext.stop();
                    logger.info('Camel stopped for {}', camelContext);
                } catch (Exception e) {
                    logger.error('Failed to stop Camel.', e);
                }
            }
        });
 
        // Added RouteBuilder from args
        for (String className : args) {
            Class<?> cls = Class.forName(className);
            if (RouteBuilder.class.isAssignableFrom(cls)) {
                Object obj = cls.newInstance();
                RouteBuilder routeBuilder = (RouteBuilder)obj;
                camelContext.addRoutes(routeBuilder);
            } else {
                throw new RuntimeException('Unable to add Camel RouteBuilder ' + className);
            }
        }
 
        // Start camel
        camelContext.start();
        logger.info('Camel started for {}', camelContext);
    }
}

Чтобы помочь вам запустить основной класс, я предоставил скрипт обертку run-java в каталоге bin проекта, чтобы вы могли быстро протестировать его без необходимости установки classpath.

1
2
$ mvn package
$ bin/run-java deng.cameldemo.CamelRunner deng.cameldemo.HelloRoute

Вы увидите, что программа загрузит HelloRoute в DefaultCamelContext и запустит его как сервер. Сам HelloRoute сгенерирует сообщение таймера на 3 секунды и отправит его регистратору, который должен распечатать на экране вашей консоли. Это будет продолжаться вечно, пока вы не нажмете CTRL+C чтобы завершить его.

ПРИМЕЧАНИЕ. Вам нужно всего лишь один раз вызвать mvn package , чтобы она упаковала все jar-файлы зависимостей, чтобы run-java автоматически обнаружил их. Если вы не собираетесь использовать maven-assembly-plugin во время фазы package , тогда используйте mvn dependency:copy-dependencies будет работать нормально.

Пробная поездка на Camel, часть 2: запуск Camel с конфигурацией Spring xml

Приведенный HelloRoute пример HelloRoute просто предоставит определение маршрута, сформированное с использованием URI компонента. Было бы хорошо, если бы мы могли настроить маршрут декларативным образом, чтобы мы могли изменить маршрут без повторной компиляции файла класса. Это будет очень удобно, особенно если вы не знакомы с опциями каждого компонента и хотите изучить и опробовать его. Ну, вот для чего camel-spring . Помимо предоставления возможности загрузки маршрута в конфигурационном файле xml, он также предоставляет очень гибкий способ регистрации bean-компонентов пользовательских служб / процессоров в контейнере Spring IoC.

Если вы увлеченный читатель, вы заметите в CamelRunner выше коде CamelRunner что у него есть дополнительная часть runWithSpringConfig . Таким образом, CamelRunner может фактически CamelRunner любой файл Spring xml и запустить контекст как сервер. Вы можете использовать это так:

1
$ bin/run-java deng.cameldemo.CamelRunner -Dspring=true config/hellocamel-spring.xml

config/hellocamel-spring.xml является просто эквивалентом нашего кода HelloRoute но в форме Spring xml:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
    xsi:schemaLocation='
 
    <camelContext id='helloCamel' xmlns='http://camel.apache.org/schema/spring'>
        <route>
            <from uri='timer://jdkTimer?period=3000'/>
            <to uri='log://deng.cameldemo.HelloCamel'/>
        </route>
    </camelContext>
 
</beans>

Это устраняет необходимость компилировать / перекомпилировать HelloRoute для определения маршрута Camel для запуска.

Создание приложения на основе сообщений с использованием Camel

Чтобы представить вам более практическую демонстрацию, я покажу вам, как настроить Camel для обработки приложения, основанного на сообщениях. Во многих ИТ-магазинах принято, что у вас есть сервер, который принимает данные сообщений в качестве входных данных и обрабатывает их. Практический вариант использования — взять любое сообщение в формате JSON, преобразовать его в объект и обработать. Чтобы сделать это в Camel, вы хотите построить маршрут, который будет принимать входные сообщения от порта TCP, а затем обрабатывать его в конвейерном потоке с любой имеющейся у вас бизнес-логикой. Вы будете запускать маршрут как сервер, а затем клиент может использовать любое средство для отправки сообщения на порт TCP. Клиент может даже быть еще одним тонким клиентским приложением Camel для отправки данных. Позвольте мне показать вам, как начать.

Написание кода на стороне сервера с использованием маршрута Camel

На стороне сервера потребуется маршрут для прослушивания через порт TCP, и это обеспечивается компонентом camel-mina . Первый шаг — вам нужен маршрут.

01
02
03
04
05
06
07
08
09
10
11
12
package deng.cameldemo;
 
import org.apache.camel.builder.RouteBuilder;
 
public class TcpMsgRoute extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        String port = System.getProperty('port', '12345');
        from('mina:tcp://localhost:' + port + '?sync=false').
            to('log:' + getClass().getName());
    }
}

Тогда следующий шаг … сделан! Нет, ты имеешь в виду, что это все для сервера? Слишком хорошо, чтобы быть правдой? Ну, давай попробуем

01
02
03
04
05
06
07
08
09
10
$ bin/run-java deng.cameldemo.CamelRunner deng.cameldemo.TcpMsgRoute -Dport=12345
15:21:41 main INFO  org.apache.camel.impl.DefaultCamelContext:1391 | Apache Camel 2.10.1 (CamelContext: camel-1) is starting
15:21:41 main INFO  org.apache.camel.management.ManagementStrategyFactory:43 | JMX enabled.
15:21:42 main INFO  org.apache.camel.impl.converter.DefaultTypeConverter:45 | Loaded 172 type converters
15:21:42 main INFO  org.apache.camel.component.mina.MinaConsumer:59 | Binding to server address: localhost/127.0.0.1:12345 using acceptor: org.apache.mina.transport.socket.nio.SocketAcceptor@2ffad8fe
15:21:42 main INFO  org.apache.camel.impl.DefaultCamelContext:2045 | Route: route1 started and consuming from: Endpoint[mina://tcp://localhost:12345?sync=true]
15:21:42 main INFO  org.apache.camel.management.DefaultManagementLifecycleStrategy:859 | StatisticsLevel at All so enabling load performance statistics
15:21:42 main INFO  org.apache.camel.impl.DefaultCamelContext:1426 | Total 1 routes, of which 1 is started.
15:21:42 main INFO  org.apache.camel.impl.DefaultCamelContext:1427 | Apache Camel 2.10.1 (CamelContext: camel-1) started in 0.505 seconds
15:21:42 main INFO  deng.cameldemo.CamelRunner:93 | Camel started for CamelContext(camel-1)

Вуаля! Сервер запущен и ожидает, пока ваши пользователи отправят сообщения через порт 12345 . Не так уж плохо для нескольких строк кода.

Написание кода на стороне клиента с помощью Camel ProducerTemplate

Поскольку наш сервер предоставляет порт TCP и принимает любое текстовое сообщение, вы можете создать любого клиента, способного записывать данные в сокет TCP. Здесь я покажу вам, как использовать Camel для написания тонкого клиента.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package deng.cameldemo.client;
 
import java.io.FileReader;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class TcpMsgSender {
    public static void main(String[] args) throws Exception {
        TcpMsgSender runner = new TcpMsgSender();
        runner.run(args);
    }
 
    private static Logger logger = LoggerFactory.getLogger(TcpMsgSender.class);
    public void run(String[] args) throws Exception {
        String fileName = args.length > 0 ? args[0] : 'data/msg.txt';
        String[] hostPort = (args.length > 1 ? args[1] : 'localhost:12345').split(':');
        String host = hostPort[0];
        String port = hostPort.length > 1 ? hostPort[1] : '12345';
        logger.info('Sending tcp message {} to host={}, port={}', new Object[]{ fileName, host, port});
 
        String text = IOUtils.toString(new FileReader(fileName));
        logger.debug('File size={}', text.length());
 
        CamelContext camelContext = new DefaultCamelContext();
        ProducerTemplate producer = camelContext.createProducerTemplate();
        producer.sendBody('mina:tcp://' + host + ':' + port + '?sync=false', text);
        logger.info('Message sent.');
    }
}

Этот TcpMsgSender может отправлять любой текстовый файл на конечную точку вашего сервера. Попробуйте это во время работы вашего сервера:

1
2
3
4
5
6
$ bin/run-java deng.cameldemo.client.TcpMsgSender data/test-msg.json localhost:12345
15:22:35 main INFO  deng.cameldemo.client.TcpMsgSender:24 | Sending tcp message data/test-msg.json to host=localhost, port=12345
15:22:35 main DEBUG deng.cameldemo.client.TcpMsgSender:27 | File size=47
15:22:35 main INFO  org.apache.camel.impl.converter.DefaultTypeConverter:45 | Loaded 172 type converters
15:22:35 main INFO  org.apache.camel.management.ManagementStrategyFactory:43 | JMX enabled.
15:22:35 main INFO  deng.cameldemo.client.TcpMsgSender:32 | Message sent.

Вы должны быть в состоянии проверить с вашего сервера вывод консоли, что он получил сообщение. Сообщение, которое я отправил, находится в data/test-msg.json , который содержит этот простой текст:

1
{ 'firstName' : 'Zemian', 'lastName' : 'Deng' }

Обратите внимание, что наш сервер просто получает простой текст и регистрирует его. Мы обсудим, как обработать сообщение дальше.

Обработка данных сообщения в формате JSON с конфигурацией Camel и Spring xml

Вы думали, что серверный код был простым сверху, угадайте снова. Вы можете заменить TcpMsgRoute несколькими простыми строками XML!

01
02
03
04
05
06
07
08
09
10
11
12
13
14
    xsi:schemaLocation='
 
    <camelContext id='tcpMsgServer' xmlns='http://camel.apache.org/schema/spring'>
        <route>
            <from uri='mina:tcp://localhost:12345?sync=false'/>
            <to uri='log://deng.cameldemo.TcpMsgServer'/>
        </route>
    </camelContext>
 
</beans>

Сохраните его как config/tcpmsgserver-spring.xml . Затем перезапустите сервер, и вы получите тот же результат, что и выше.

1
$ bin/run-java deng.cameldemo.CamelRunner -Dspring=true config/tcpmsgserver-spring.xml

Теперь давайте улучшим вышеупомянутый xml для дальнейшей обработки данных сообщения JSON. Мы хотим преобразовать простой текст в объект Java, а затем обработать его с помощью пользовательского компонента. Для этого сначала нужно добавить немаршальный компонент к маршруту. Это где camel-jackson вступает в игру. В нашей демонстрации шаг демаршаллинга преобразует текст JSON в java.util.Map а затем передает его компоненту с именем myMsgProcessor . Давайте создадим новый XML-файл с именем config/tcpmsgserver-json-spring.xml следующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
    xsi:schemaLocation='
 
    <camelContext id='tcpMsgServer' xmlns='http://camel.apache.org/schema/spring'>
        <route>
            <from uri='mina:tcp://localhost:12345?sync=false'/>
            <to uri='log://deng.cameldemo.TcpMsgServer'/>
            <unmarshal>
                <json library='Jackson'/>
            </unmarshal>
            <to uri='bean:myMsgProcessor?method=process'/>
        </route>
    </camelContext>
 
    <bean id='myMsgProcessor' class='deng.cameldemo.MyMsgProcessor'>
    </bean>
 
</beans>

myMsgProcessor — это bean-компонент Spring, в котором мы предоставляем собственный логический код для обработки данных. На данный момент у нас есть полный Java-объект для манипулирования. Содержимое процессора может быть любым POJO с именем метода, указанным в URI. Вот пример один:

01
02
03
04
05
06
07
08
09
10
11
12
13
package deng.cameldemo;
 
import org.apache.camel.builder.RouteBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
 
public class MyMsgProcessor {
    private static Logger logger = LoggerFactory.getLogger(MyMsgProcessor.class);
    public void process(Map<String, String> data) {
        logger.info('We should slice and dice the data: ' + data);
    }
}

Попробуйте перезапустить сервер с новым XML-файлом, приведенным выше, и вы сможете повторно вызвать ту же команду клиента, чтобы протестировать ее. Вот пример вывода моего сервера:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
$ bin/run-java deng.cameldemo.CamelRunner -Dspring=true config/tcpmsgserver-json-spring.xml
17:05:25 main INFO  org.springframework.context.support.FileSystemXmlApplicationContext:456 | Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@4200309: startup date [Sat Sep 15 17:05:25 EDT 2012]; root of context hierarchy
17:05:25 main INFO  org.springframework.beans.factory.xml.XmlBeanDefinitionReader:315 | Loading XML bean definitions from file [/Users/zemian/projects/sandbox/camel-demo/config/tcpmsgserver-json-spring.xml]
17:05:27 main INFO  org.springframework.beans.factory.support.DefaultListableBeanFactory:557 | Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@27b75165: defining beans [template,consumerTemplate,tcpMsgServer:beanPostProcessor,tcpMsgServer,myMsgProcessor]; root of factory hierarchy
17:05:27 main INFO  org.apache.camel.spring.SpringCamelContext:1391 | Apache Camel 2.10.1 (CamelContext: tcpMsgServer) is starting
17:05:27 main INFO  org.apache.camel.management.ManagementStrategyFactory:43 | JMX enabled.
17:05:27 main INFO  org.apache.camel.impl.converter.DefaultTypeConverter:45 | Loaded 172 type converters
17:05:28 main INFO  org.apache.camel.component.mina.MinaConsumer:59 | Binding to server address: localhost/127.0.0.1:12345 using acceptor: org.apache.mina.transport.socket.nio.SocketAcceptor@5a3cae4a
17:05:28 main INFO  org.apache.camel.spring.SpringCamelContext:2045 | Route: route1 started and consuming from: Endpoint[mina://tcp://localhost:12345?sync=false]
17:05:28 main INFO  org.apache.camel.management.DefaultManagementLifecycleStrategy:859 | StatisticsLevel at All so enabling load performance statistics
17:05:28 main INFO  org.apache.camel.spring.SpringCamelContext:1426 | Total 1 routes, of which 1 is started.
17:05:28 main INFO  org.apache.camel.spring.SpringCamelContext:1427 | Apache Camel 2.10.1 (CamelContext: tcpMsgServer) started in 0.695 seconds
17:05:28 main INFO  deng.cameldemo.CamelRunner:61 | Spring started.
17:05:35 Camel (tcpMsgServer) thread #3 - MinaThreadPool INFO  deng.cameldemo.TcpMsgServer:96 | Exchange[ExchangePattern:InOnly, BodyType:String, Body:{ 'firstName' : 'Zemian', 'lastName' : 'Deng' }]
17:05:35 Camel (tcpMsgServer) thread #3 - MinaThreadPool INFO  deng.cameldemo.MyMsgProcessor:11 | We should slice and dice the data: {lastName=Deng, firstName=Zemian}

Обратите внимание, что Camel автоматически преобразует формат данных в вашем маршруте! Наш клиент отправляет только простой текст в формате JSON, но когда сервер получает его, он демарширует его с помощью библиотеки Джексона, а затем преобразует его в объект Java-карты. Затем он передает объект карты в наш компонент EJB. Кроме того, в этой демонстрации я решил использовать универсальный java.util.Map качестве аргумента метода процессора (который является выводом демаршала JSON), но вы можете легко определить свой собственный тип бизнес-данных, такой как MyCustomerData . Это показывает мощь Camel, поскольку вам не нужно помещать сообщение в свой поток, а беспокоиться только о том, чтобы записать свой «процессор» в виде POJO. Camel «склеит» компоненты вместе, чтобы сформировать маршрут и передать данные сообщения по конвейеру.

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

Ну вот и все на сегодня, ребята. Я надеюсь, вам понравилась поездка на верблюде.

Приятного кодирования и не забудьте поделиться!

Ссылка: Создание приложения на основе сообщений с использованием Camel от нашего партнера по JCG Земьяна Дена в блоге A Programmer’s Journal .