Apache Camel+Spring Boot 2でHello World（コンソールアプリ編）

# はじめに

以下の組み合わせで、1秒おきに「Hello World」を出力するコンソールアプリケーションを作成します。

- Apache Camel 2.3.0
- Spring Boot 2.1.1
- JDK8
- Eclipse Photon(4.8.0)
- Maven

REST API編は以下になります。

[Apache Camel+Spring Boot 2でHello World（REST API編）](https://qiita.com/mkyz08/items/39007d9dc3e10eecc696)

# Apache Camelとは

Spring Bootは説明の必要はないと思いますので、Apache Camelだけ簡単に説明します。

Apache Camelは、システム間の統合のためのミドルウェア（フレームワーク）とよく説明されています。システム間の統合はEnterprise Integration Patternsというベストプラクティスがあり、Camelではそれを簡単に実現することができます。
このように書くと小難しいように聞こえてしまい、無駄に敷居が高くなっているような気がします。
実際には「別のシステムからリクエストを受けて、何らかの処理をして、どこかへ送信・格納（DBやキュー）する。」といったことが簡単にできるフレームワークと思えばよいです。
REST/SOAP、データベース(JDBC, MongoDB, DynamoDB, etc)、ファイル、メッセージキュー（ActiveMQ, Kafka, RabbitMQ, etc）、メール、MQTTなど、様々なものと連係することでき、それを実現するための部品がコンポーネントと呼ばれます。
コンポーネントは200近くにのぼり、繋げたい相手のコンポーネントは大抵見つけることができます。
「何らかの処理をして」の部分も、データ変換、フォーマット変換、ルーティング、エラー処理等の機能は網羅されており、あらゆるアプリケーションで利用できるフレームワークです。

# Eclipseでプロジェクトを作成する

まず、Mavenプロジェクトを新規に作成します。
「Mavenプロジェクト」を選択して「次へ」。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/0d7b06ef-0ce3-742d-7bbe-ba14be7f690d.png)

特に変更せず、「次へ」。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/8e7142a2-74ac-bf72-03b6-9d763fb127fc.png)

「maven-archetype-quickstart」を選択して、「次へ」。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/3801a22a-56c2-51c8-9fe7-17697c3f03b9.png)

プロジェクトの情報を入力して、「完了」。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/851f0041-d67e-0686-f018-116a03a40f12.png)

これでプロジェクトの作成は完了。


# pom.xmlを修正

pom.xmlを以下のように修正する。

```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>mkyz08.sample</groupId>
	<artifactId>camel-springboot-test</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>camel-springboot-test</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
		<maven.compiler.target>${java.version}</maven.compiler.target>
		<maven.compiler.source>${java.version}</maven.compiler.source>
		<camel-version>2.23.0</camel-version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.apache.camel</groupId>
				<artifactId>camel-parent</artifactId>
				<version>${camel-version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-stream</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

```

# プログラムを作成

以下のようにメインプログラムを作成する。

```Application.java
package mkyz08.example;

import org.apache.camel.spring.boot.CamelSpringBootApplicationController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new SpringApplication(Application.class).run(args);
        CamelSpringBootApplicationController applicationController =
                applicationContext.getBean(CamelSpringBootApplicationController.class);
        applicationController.run();
    }

}
```

以下は、普通のSpring Bootのアプリケーションの起動ですね。

```java
ApplicationContext applicationContext = new SpringApplication(Application.class).run(args);
```

以下が普通のSpring Bootのアプリケーションの起動と違うところです。

CamelSpringBootApplicationControllerクラスのrunメソッドを実行することで、デーモンスレッドとして実行を続けることができます。こうしないと、コンソールアプリは起動してそのまま終了してしまいます。

```java
        CamelSpringBootApplicationController applicationController =
                applicationContext.getBean(CamelSpringBootApplicationController.class);
        applicationController.run();
```

設定ファイルは以下のとおりです。
「spring.main.web-application-type=none」とすることで、Tomcatが起動しないようになります。
「timer.period」はアプリケーションの設定で、Hello Worldを1秒おきに表示するときの設定値として使用します。

```src/main/resources/application.properties
camel.springboot.name = MyCamelApp
spring.main.web-application-type=none
timer.period = 1000
```

最後にCamelのrouteを作成します。
Camelのroute定義のため、クラスにComponentアノテーションを付与し、RouteBuilderクラスを継承しています。
そして、configureメソッドをオーバーライドして、routeの内容をコーディングします。

```HelloWorldRoute.java
package mkyz08.example;

import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Component
public class HelloWorldRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
		from("timer://exampleTimer?period={{timer.period}}")
				.routeId("hello world route")
				.setBody(simple("Hello World at ${header.firedTime}"))
				.to("stream:out");
    }
}
```

以下がrouteの内容で、

- 「timer://exampleTimer?period={{timer.period}}」で、1秒おきに実行するタイマーを定義
- 「.routeId("hello world route")」、これはルートIDを指定しているだけ
- 「.setBody(simple("Hello World at ${header.firedTime}"))」、ExchangeのBODYにHello Worldの文字列を設定
- 「.to("stream:out")」でExchangeのBODYに入っている、Hello Worldの文字列をコンソールに出力しています。

```java
		from("timer://exampleTimer?period={{timer.period}}")
				.routeId("hello world route")
				.setBody(simple("Hello World at ${header.firedTime}"))
				.to("stream:out");
```


# Hello Worldコンソールアプリケーションを実行する

作成したプログラムを実行すると、以下のようにコンソールに出力されます。

```
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.0.RELEASE)

2018-12-06 14:59:46.472  INFO 17612 --- [           main] mkyz08.example.Application               : Starting Application on mky-PC with PID 17612 (C:\pleiades\workspace\camel-springboot-test\target\classes started by mky in C:\pleiades\workspace\camel-springboot-test)
2018-12-06 14:59:46.474  INFO 17612 --- [           main] mkyz08.example.Application               : No active profile set, falling back to default profiles: default
2018-12-06 14:59:47.516  INFO 17612 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.apache.camel.spring.boot.CamelAutoConfiguration' of type [org.apache.camel.spring.boot.CamelAutoConfiguration$$EnhancerBySpringCGLIB$$9ed7a086] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-12-06 14:59:47.731  INFO 17612 --- [           main] o.a.c.i.converter.DefaultTypeConverter   : Type converters loaded (core: 195, classpath: 1)
2018-12-06 14:59:48.080  INFO 17612 --- [           main] o.a.camel.spring.boot.RoutesCollector    : Loading additional Camel XML routes from: classpath:camel/*.xml
2018-12-06 14:59:48.080  INFO 17612 --- [           main] o.a.camel.spring.boot.RoutesCollector    : Loading additional Camel XML rests from: classpath:camel-rest/*.xml
2018-12-06 14:59:48.086  INFO 17612 --- [           main] o.a.camel.spring.SpringCamelContext      : Apache Camel 2.23.0 (CamelContext: MyCamelApp) is starting
2018-12-06 14:59:48.086  INFO 17612 --- [           main] o.a.c.m.ManagedManagementStrategy        : JMX is enabled
2018-12-06 14:59:48.274  INFO 17612 --- [           main] o.a.camel.spring.SpringCamelContext      : StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
2018-12-06 14:59:48.385  INFO 17612 --- [           main] o.a.camel.spring.SpringCamelContext      : Route: hello world route started and consuming from: timer://exampleTimer?period=1000
2018-12-06 14:59:48.387  INFO 17612 --- [           main] o.a.camel.spring.SpringCamelContext      : Total 1 routes, of which 1 are started
2018-12-06 14:59:48.390  INFO 17612 --- [           main] o.a.camel.spring.SpringCamelContext      : Apache Camel 2.23.0 (CamelContext: MyCamelApp) started in 0.302 seconds
2018-12-06 14:59:48.394  INFO 17612 --- [           main] mkyz08.example.Application               : Started Application in 2.316 seconds (JVM running for 2.825)
Hello World at Thu Dec 06 14:59:49 JST 2018
Hello World at Thu Dec 06 14:59:50 JST 2018
Hello World at Thu Dec 06 14:59:51 JST 2018
```

# 実行可能なjarファイルを作成する

実行可能なjarファイルを作成するため、以下のように「実行構成」でゴールに「clean install spring-boot:repackage」と入力し、実行します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179607/0fc180d3-ff0c-0c53-cc95-f2c928f89b0a.png)

実行に成功すると以下のようなログが出力されます。


```
[INFO] --- spring-boot-maven-plugin:2.1.1.RELEASE:repackage (default-cli) @ camel-springboot-test ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.930 s
[INFO] Finished at: 2018-12-06T13:03:00+09:00
[INFO] ------------------------------------------------------------------------
```

実行可能なjarファイルはプロジェクトの「target」とディレクトリに作成されており、以下のコマンドで実行できます。

```
java -jar camel-springboot-test-0.0.1-SNAPSHOT.jar
```



# 参考

- [Apache Camel公式サイト　Spring Boot](https://camel.apache.org/components/latest/spring-boot.html)

- [Apache Camel with Spring Boot](https://medium.com/@mzimecki/spring-boot-apache-camel-web-service-a90696d8ac36)

- [Apache Camel公式サイト　Spring Bootサンプル](https://github.com/apache/camel/tree/master/components/camel-spring-boot)