1. Información general
En esencia, Apache Camel es un motor de integración que, en pocas palabras, se puede utilizar para facilitar las interacciones entre una amplia y variada gama de tecnologías.
Estos puentes entre servicios y tecnologías se denominan rutas. Las rutas se implementan en un motor ( CamelContext ) y se comunican con los llamados "mensajes de intercambio".
2. Dependencias de Maven
Para comenzar, necesitaremos incluir dependencias para Spring Boot, Camel, Rest API con Swagger y JSON:
org.apache.camel camel-servlet-starter ${camel.version} org.apache.camel camel-jackson-starter ${camel.version} org.apache.camel camel-swagger-java-starter ${camel.version} org.apache.camel camel-spring-boot-starter ${camel.version} org.springframework.boot spring-boot-starter-web ${spring-boot-starter.version}
Las últimas versiones de las dependencias de Apache Camel se pueden encontrar aquí.
3. La clase principal
Primero creemos una aplicación Spring Boot :
@SpringBootApplication @ComponentScan(basePackages="com.baeldung.camel") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
4. Configuraciones de camello para Spring Boot
Configuremos ahora nuestra aplicación con Spring, comenzando con los archivos de configuración (propiedades).
Por ejemplo, configuremos un registro para nuestra aplicación en un archivo application.properties en src / main / resources :
logging.config=classpath:logback.xml camel.springboot.name=MyCamel server.address=0.0.0.0 management.address=0.0.0.0 management.port=8081 endpoints.enabled = true endpoints.health.enabled = true
Este ejemplo muestra un archivo application.properties que también establece la ruta a una configuración de Logback. Al configurar la IP en "0.0.0.0", restringimos completamente el acceso de administración y administración en el servidor web proporcionado por Spring Boot. Además, habilitamos el acceso de red necesario a los puntos finales de nuestras aplicaciones, así como a los puntos finales de verificación de estado.
Otro archivo de configuración es application.yml . En él, agregaremos algunas propiedades para ayudarnos a inyectar valores en nuestras rutas de aplicación:
server: port: 8080 camel: springboot: name: ServicesRest management: port: 8081 endpoints: enabled: false health: enabled: true quickstart: generateOrderPeriod: 10s processOrderPeriod: 30s
5 . Configuración del Servlet Camel
Una forma de comenzar a usar Camel es registrarlo como servlet, para que pueda interceptar las solicitudes HTTP y redirigirlas a nuestra aplicación.
Como se mencionó anteriormente, al comenzar con la versión 2.18 de Camel y posteriores, podemos aprovechar nuestro application.yml , creando un parámetro para nuestra URL final. Posteriormente se inyectará en nuestro código Java:
baeldung: api: path: '/camel'
De regreso a nuestra clase Application , necesitamos registrar el servlet Camel en la raíz de nuestra ruta de contexto, que se inyectará desde la referencia baeldung.api.path en application.yml cuando se inicie la aplicación:
@Value("${baeldung.api.path}") String contextPath; @Bean ServletRegistrationBean servletRegistrationBean() { ServletRegistrationBean servlet = new ServletRegistrationBean (new CamelHttpTransportServlet(), contextPath+"/*"); servlet.setName("CamelServlet"); return servlet; }
A partir de la versión 2.19 de Camel, esta configuración se ha eliminado ya que CamelServlet está configurado de forma predeterminada en “/ camel” .
6. Construir una ruta
Comencemos a hacer una ruta extendiendo la clase RouteBuilder de Camel y configurándola como @Component para que la rutina de escaneo de componentes pueda ubicarla durante la inicialización del servidor web:
@Component class RestApi extends RouteBuilder { @Override public void configure() { CamelContext context = new DefaultCamelContext(); restConfiguration()... rest("/api/")... from("direct:remoteService")... } }
En esta clase, anulamos el método configure () de la clase RouteBuilder de Camel .
Camel siempre necesita una instancia de CamelContext , el componente principal donde se guardan los mensajes entrantes y salientes.
En este ejemplo simple, DefaultCamelContext es suficiente ya que simplemente enlaza mensajes y enruta a él, como el servicio REST que vamos a crear.
6.1. El restConfiguration () Ruta
A continuación, creamos una declaración REST para los puntos finales que planeamos crear en el método restConfiguration () :
restConfiguration() .contextPath(contextPath) .port(serverPort) .enableCORS(true) .apiContextPath("/api-doc") .apiProperty("api.title", "Test REST API") .apiProperty("api.version", "v1") .apiContextRouteId("doc-api") .component("servlet") .bindingMode(RestBindingMode.json)
Aquí, registramos la ruta de contexto con nuestro atributo inyectado del archivo YAML. La misma lógica se aplicó al puerto de nuestra aplicación. CORS está habilitado, lo que permite el uso entre sitios de este servicio web. El modo de enlace permite y convierte argumentos a nuestra API.
A continuación, agregamos la documentación de Swagger al URI, el título y la versión que configuramos previamente. A medida que creamos métodos / puntos finales para nuestro servicio web REST, la documentación de Swagger se actualizará automáticamente.
Este contexto Swagger es en sí mismo una ruta Camel, y podemos ver información técnica sobre él en el registro del servidor durante el proceso de inicio. Nuestra documentación de ejemplo se sirve de forma predeterminada en // localhost: 8080 / camel / api-doc.
6.2. El resto () Ruta
Ahora, implementemos la llamada al método rest () desde el método configure () enumerado anteriormente:
rest("/api/") .id("api-route") .consumes("application/json") .post("/bean") .bindingMode(RestBindingMode.json_xml) .type(MyBean.class) .to("direct:remoteService");
Este método es bastante sencillo para aquellos familiarizados con las API. El id es la identificación de la ruta dentro de CamelContext . La siguiente línea define el tipo MIME. El modo de enlace se define aquí para mostrar que podemos establecer un modo en restConfiguration () .
El método post () agrega una operación a la API, generando un punto final " POST / bean ", mientras que MyBean (un bean Java normal con un ID de número entero y un nombre de cadena ) define los parámetros esperados.
De manera similar, las acciones HTTP como GET, PUT y DELETE también están disponibles en forma de get () , put () , delete () .
Finalmente, el método to () crea un puente a otra ruta. Aquí le dice a Camel que busque dentro de su contexto / motor a otra ruta que vamos a crear - que es nombrada y detectada por el valor / id " directo: ... ", que coincide con la ruta definida en el método from () .
6.3. The from() Route With transform()
When working with Camel, a route receives parameters and then converts, transforms and process these parameters. After that, it sends these parameters to another route that forwards the result to the desired output (a file, a database, an SMTP server or a REST API response).
In this article, we only create another route inside the configure() method that we are overriding. It will be the destination route for our last to() route:
from("direct:remoteService") .routeId("direct-route") .tracing() .log(">>> ${body.id}") .log(">>> ${body.name}") .transform().simple("Hello ${in.body.name}") .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200));
The from() method follows the same principles and has many of the same methods as the rest() method, except that it consumes from the Camel context messages. This is the reason for the parameter “direct-route“, that creates a link to the aforementioned method rest().to().
Many other conversions are available, including extraction as Java primitives (or objects) and sending it down to a persistence layer. Notice that the routes always read from incoming messages, so that chained routes will ignore outgoing messages.
Our example is ready, and we can try it:
- Run the prompt command: mvn spring-boot:run
- Do a POST request to //localhost:8080/camel/api/bean with header parameters: Content-Type: application/json, and a payload {“id”: 1,”name”: “World”}
- We should receive a return code of 201 and the response: Hello, World
6.4. The SIMPLE Scripting Language
The example outputs logging using the tracing() method. Notice that we've used the ${} placeholders; these are part of a scripting language that belongs to Camel called SIMPLE. It is applied to messages that are exchanged over the route, like the body of the in-message.
In our example, we are using SIMPLE to output to the log the bean attributes that are inside the Camel message body.
We can also use it to do simple transformations as well, as was shown with the transform() method.
6.5. The from() Route With process()
Let's do something more meaningful, such as calling a service layer to return processed data. SIMPLE isn't meant for heavy data processing, so let's replace the transform() with a process() method:
from("direct:remoteService") .routeId("direct-route") .tracing() .log(">>> ${body.id}") .log(">>> ${body.name}") .process(new Processor() { @Override public void process(Exchange exchange) throws Exception { MyBean bodyIn = (MyBean) exchange.getIn().getBody(); ExampleServices.example(bodyIn); exchange.getIn().setBody(bodyIn); } }) .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200));
This allows us to extract the data into a bean, the same one previously defined on the type() method, and process it in our ExampleServices layer.
Since we set the bindingMode() to JSON previously, the response already is in a proper JSON format, generated based on our POJO. This implies that for an ExampleServices class:
public class ExampleServices { public static void example(MyBean bodyIn) { bodyIn.setName( "Hello, " + bodyIn.getName() ); bodyIn.setId(bodyIn.getId() * 10); } }
The same HTTP request now returns with a response code 201 and body: {“id”: 10,”name”: “Hello, World”}.
7. Conclusion
With a few lines of code, we managed to create a relatively complete application. All dependencies are built, managed and run automatically with a single command. Moreover, we can create APIs that tie together all sorts of technologies.
This approach is also very container friendly, resulting in a very lean server environment that can be easily replicated on demand. The extra configuration possibilities can easily be incorporated into a container template configuration file.
Este ejemplo de REST se puede encontrar en GitHub.
Finalmente, más allá de las API de filter () , process () , transform () y marshall () , hay muchos otros patrones de integración y manipulaciones de datos disponibles en Camel:
- Patrones de integración de camellos
- Guía del usuario de camello
- Lenguaje simple de camello