{{announcement.body}}
{{announcement.title}}

Creating Camel 3 CDI Microservices

DZone 's Guide to

Creating Camel 3 CDI Microservices

In this post, I want to go through some libraries that allow creating microservices within a camel ecosystem (Pure Apache Camel 3 microservices).

· Microservices Zone ·
Free Resource

As many people already know, Apache Camel is an open-source project that makes easy implement integration projects, in this post I want to go through some libraries that allow creating microservices within a camel ecosystem (Pure Apache Camel 3 microservices).

In order to create microservices with camel we can combine some camel modules such:

  • Camel-undertow — It provides an HTTP/Websockets server
  • Camel-swagger-java — Enable document our services and generate automatically swagger definitions.
  • Camel-cdi — Bring a dependency injection capability into Apache Camel projects.

So let's talk shop.

I used the Camel CDI archetype to create my CDI project.

Plain Text
 







The project generated is a plain Camel CDI java project, then, how I can convert this in a microservice?

First of all, we need a class with a main method like this:

Java
 




xxxxxxxxxx
1
11


 
1
import org.apache.camel.cdi.Main;
2
 
          
3
public class UserMainApp {
4
    
5
    public static void main(String... args) throws Exception {
6
        Main main = new Main();
7
        main.run(args);
8
        main.close();
9
    }
10
    
11
}



Please note the above snippet:

  • Use org.apache.camel.cdi.Main class instead of org.apache.camel.main.Main class.
  • It does not register any route with the main.addRoutesBuilder method is because of CDI auto-scan all components in the classpath.

Secondly, we have to add Undertow, Swagger and JSON dependencies in the pom.xml.

XML
 




xxxxxxxxxx
1
24


1
        <!-- Undertow -->
2
        <dependency>
3
            <groupId>org.apache.camel</groupId>
4
            <artifactId>camel-undertow</artifactId>
5
        </dependency>
6
 
          
7
        <!-- Stream -->
8
        <dependency>
9
            <groupId>org.apache.camel</groupId>
10
            <artifactId>camel-stream</artifactId>
11
        </dependency>
12
 
          
13
        <!-- swagger -->
14
        <dependency>
15
            <groupId>org.apache.camel</groupId>
16
            <artifactId>camel-swagger-java</artifactId>
17
        </dependency>
18
 
          
19
        <!-- JSON -->
20
        <dependency>
21
            <groupId>org.apache.camel</groupId>
22
            <artifactId>camel-jackson</artifactId>
23
        </dependency>



The above dependencies are not enough, we have to add another couple to allow the main class works.

XML
 




xxxxxxxxxx
1
11


 
1
        <!-- Enabling org.apache.camel.cdi.Main -->
2
        <dependency>
3
            <groupId>org.apache.deltaspike.cdictrl</groupId>
4
            <artifactId>deltaspike-cdictrl-weld</artifactId>
5
            <version>1.9.0</version>
6
        </dependency>
7
        <dependency>
8
            <groupId>org.jboss.weld.se</groupId>
9
            <artifactId>weld-se-shaded</artifactId>
10
            <version>3.0.5.Final</version>
11
        </dependency>



Third, we are ready to implement the Service class and the Camel Route consuming the method.

The Camel CDI detect Java Dependency Injection annotations

Java
 




xxxxxxxxxx
1


1
import javax.inject.Named;
2
 
          
3
@Named("userService")
4
public class UserService {
5
  ...
6
}



The camel route can use the service either making direct reference in the route or using the @Inject annotation.

Below route declare undertow as a server providing service in the port 8080 for all host's IPs available, and using the bean annotated before (bean:userService), all of this perfectly documented with swagger.

Java
 




xxxxxxxxxx
1
29


 
1
public class UserRouteBuilder extends RouteBuilder {
2
 
          
3
    @Override
4
    public void configure() throws Exception {
5
 
          
6
        // configure we want to use undertow as the component for the rest DSL
7
        // and we enable json binding mode
8
        restConfiguration().component("undertow")
9
            .bindingMode(RestBindingMode.json)
10
            .dataFormatProperty("prettyPrint", "true")
11
            // setup context path on all IPs and port 8080 
12
            .contextPath("/").host("0.0.0.0").port(8080)
13
            // add swagger api-doc out of the box
14
            .apiContextPath("/api-doc")
15
                .apiProperty("api.title", "User API").apiProperty("api.version", "1.0.0")
16
                // and enable CORS
17
                .apiProperty("cors", "true");
18
 
          
19
        // this user REST service is json only
20
        rest("/user").description("User rest service")
21
            .consumes("application/json").produces("application/json")
22
 
          
23
            .get("/findAll").description("Find all users")
24
                .responseMessage().code(200).message("All users").endResponseMessage()
25
                .to("bean:userService?method=listUsers");
26
    }
27
 
          
28
}



Fourth, time to package and generate the docker image.

Packaging

I am conscious can be opinionated but I choose not to create a fat (uber) jar, instead of that I am using maven-dependency-plugin and manipulating the generation of the jar manifest.

XML
 




x


 
1
<!-- Build an executable JAR with full list of dependencies-->
2
<plugin>
3
    <groupId>org.apache.maven.plugins</groupId>
4
    <artifactId>maven-jar-plugin</artifactId>
5
    <version>2.4</version>
6
    <configuration>
7
        <archive>
8
            <manifest>
9
                <addClasspath>true</addClasspath>
10
                <mainClass>edu.emmerson.camel3.cdi.user.UserMainApp</mainClass>
11
                <classpathPrefix>dependency-jars/</classpathPrefix>
12
            </manifest>
13
        </archive>
14
    </configuration>
15
</plugin>
16
<!-- Copying all dependencies into a folder in the classpath -->
17
<plugin>
18
    <groupId>org.apache.maven.plugins</groupId>
19
    <artifactId>maven-dependency-plugin</artifactId>
20
    <executions>
21
        <execution>
22
            <id>copy-dependencies</id>
23
            <phase>package</phase>
24
            <goals>
25
                <goal>copy-dependencies</goal>
26
            </goals>
27
            <configuration>
28
                <outputDirectory>${project.build.directory}/dependency-jars/</outputDirectory>
29
            </configuration>
30
        </execution>
31
    </executions>
32
</plugin>           



Generating the Docker Image

Yes, like many others I used docker-maven-plugin with OpenJDK:8u121-alpine docker image.

XML
 




xxxxxxxxxx
1
33


1
<plugin>
2
    <groupId>com.spotify</groupId>
3
    <artifactId>docker-maven-plugin</artifactId>
4
    <configuration>
5
        <imageName>${project.artifactId}</imageName>
6
        <baseImage>openjdk:8u121-alpine</baseImage>
7
        <workdir>/opt/${project.artifactId}</workdir>
8
        <exposes>
9
            <expose>8080</expose>
10
        </exposes>
11
        <entryPoint>["java", "-jar", "/opt/${project.artifactId}/${project.build.finalName}.jar"]</entryPoint>
12
        <resources>
13
            <resource>
14
                <targetPath>.</targetPath>
15
                <directory>${project.build.directory}</directory>
16
                <include>${project.build.finalName}.jar</include>
17
            </resource>
18
            <resource>
19
                <targetPath>dependency-jars</targetPath>
20
                <directory>${project.build.directory}/dependency-jars</directory>
21
                <include>*.jar</include>
22
            </resource>
23
        </resources>
24
        <imageTags>
25
            <imageTag>${project.version}</imageTag>
26
            <imageTag>latest</imageTag>
27
        </imageTags>
28
        <labels>
29
            <label>Author=Emmerson</label>
30
            <label>Type=POC</label>
31
        </labels>
32
    </configuration>
33
</plugin>



To build the image please execute the following command line:

Shell
 




xxxxxxxxxx
1


1
mvn clean package docker:build



Fifth, you can start and test the docker image.

Shell
 




xxxxxxxxxx
1


 
1
docker run -d -p 8080:8080 cdi-user:1.0-SNAPSHOT
2
sleep 2
3
curl http://0.0.0.0:8080/user/findAll
4
 
          



Finally, you can find some full examples at my GitHub account https://github.com/Emmerson-Miranda/camel/tree/master/camel3-cdi


Wrapping Up

Create microservices with Camel 3 is a straightforward process, and meet the requirement for those people who claim dependency injection features as a part of the development process.

I have to highlight other projects around Camel, like CamelK (Camel serverless on top of Kubernetes) and Quarkus (combined with GraalVM can create native executable services similar to golang).

Thanks for spending your time reading this.

Topics:
camel ,cdi ,microservices ,tutorial ,usermainapp

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}