Apache Camel avec botte à ressort

Apache Camel avec botte à ressort

1. Vue d'ensemble

Apache Camel est essentiellement un moteur d'intégration qui, en termes simples, peut être utilisé pour faciliter les interactions entre un large éventail de technologies.

Ces ponts entre services et technologies sont appelésroutes.. Les routes sont implémentées sur un moteur (lesCamelContext), et elles communiquent avec des «messages d'échange».

2. Dépendances Maven

Pour commencer, nous devrons inclure des dépendances pour Spring Boot, Camel, Rest API avec Swagger et 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}
    

Les dernières versions des dépendances d'Apache Camel peuvent être trouvéeshere.

3. La classe principale

Commençons par créer un Spring BootApplication:

@SpringBootApplication
@ComponentScan(basePackages="com.example.camel")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4. Configurations de chameau pour Spring Boot

Configurons maintenant notre application avec Spring, en commençant par les fichiers de configuration (propriétés).

Par exemple, configurons un journal pour notre application sur un fichierapplication.properties danssrc/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

Cet exemple montre un fichierapplication.properties qui définit également le chemin vers une configuration Logback. En définissant l'adresse IP sur «0.0.0.0», nous limitons totalement l'accès deadmin etmanagement au serveur Web fourni par Spring Boot. Nous activons également l'accès réseau nécessaire aux noeuds finaux de nos applications ainsi qu'aux noeuds finaux de vérification de l'état.

Un autre fichier de configuration est leapplication.yml. Nous y ajouterons quelques propriétés pour nous aider à injecter des valeurs dans nos routes d'application:

server:
  port: 8080
camel:
  springboot:
    name: ServicesRest
management:
  port: 8081
endpoints:
  enabled: false
  health:
    enabled: true
quickstart:
  generateOrderPeriod: 10s
  processOrderPeriod: 30s

5. Setting up the Camel Servlet

Une façon de commencer à utiliser Camel consiste à l'enregistrer en tant que servlet afin qu'il puisse intercepter les demandes HTTP et les rediriger vers notre application.

Comme mentionné précédemment, avec la version 2.18 et inférieure de Camel, nous pouvons tirer parti de nosapplication.yml - en créant un paramètre pour notre URL finale. Plus tard, il sera injecté dans votre code Java:

example:
  api:
    path: '/camel'

De retour à notre classeApplication, nous devons enregistrer la servlet Camel à la racine de notre chemin de contexte, qui va être injecté à partir de la référenceexample.api.path dans lesapplication.yml lorsque l'application démarre :

@Value("${example.api.path}")
String contextPath;

@Bean
ServletRegistrationBean servletRegistrationBean() {
    ServletRegistrationBean servlet = new ServletRegistrationBean
      (new CamelHttpTransportServlet(), contextPath+"/*");
    servlet.setName("CamelServlet");
    return servlet;
}

Depuis la version 2.19 de Camel, cette configuration a été supprimée car leCamelServlet est par défaut défini sur“/camel”.

6. Construire un itinéraire

Commençons par créer un itinéraire en étendant la classeRouteBuilder à partir de Camel et en la définissant comme@Component afin que la routine d'analyse des composants puisse la localiser lors de l'initialisation du serveur Web:

@Component
class RestApi extends RouteBuilder {
    @Override
    public void configure() {
        CamelContext context = new DefaultCamelContext();

        restConfiguration()...
        rest("/api/")...
        from("direct:remoteService")...
    }
}

Dans cette classe, nous remplaçons la méthodeconfigure() de la classeRouteBuilder de Camel.

Camel always needs a CamelContext instance - le composant principal où sont conservés les messages entrants et sortants.

Dans cet exemple simple,DefaultCamelContext suffit car il lie simplement les messages et les achemine, comme le service REST que nous allons créer.

6.1. La routerestConfiguration()

Ensuite, nous créons une déclaration REST pour les points de terminaison que nous prévoyons de créer dans la méthoderestConfiguration():

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)

Ici, nous enregistrons le chemin de contexte avec notre attribut injecté à partir du fichier YAML. La même logique a été appliquée au port de notre application. CORS est activé, permettant une utilisation intersite de ce service Web. Le mode de liaison autorise et convertit les arguments vers notre API.

Ensuite, nous ajoutons la documentation Swagger à l’URI, au titre et à la version précédemment définis. Au fur et à mesure que nous créons des méthodes / points de terminaison pour notre service Web REST, la documentation Swagger sera automatiquement mise à jour.

Ce contexte Swagger est lui-même une route de chameaux et nous pouvons voir des informations techniques à ce sujet dans le journal du serveur au cours du processus de démarrage. Notre exemple de documentation est par défaut servi àhttp://localhost:8080/camel/api-doc.

6.2. La routerest()

Maintenant, implémentons l'appel de méthoderest() à partir de la méthodeconfigure() répertoriée ci-dessus:

rest("/api/")
  .id("api-route")
  .consumes("application/json")
  .post("/bean")
  .bindingMode(RestBindingMode.json_xml)
  .type(MyBean.class)
  .to("direct:remoteService");

Cette méthode est assez simple pour ceux qui sont familiers avec les API. Leid est l'identification de la route à l'intérieur desCamelContext. La ligne suivante définit le type MIME. Le mode de liaison est défini ici pour montrer que nous pouvons définir un mode sur lesrestConfiguration().

La méthodepost() ajoute une opération à l'API, générant un point de terminaison «POST /bean», tandis que leMyBean (un bean Java standard avec unInteger id etString name ) définit les paramètres attendus.

De même, les actions HTTP telles que GET, PUT et DELETE sont également disponibles sous la forme deget(),put(),delete().

Enfin, la méthodeto() crée un pont vers une autre route. Ici, il dit à Camel de rechercher dans son contexte / moteur vers une autre route que nous allons créer - qui est nommée et détectée par la valeur / id «direct: …», correspondant à la route définie dans lefrom() méthode.

6.3. La routefrom() avectransform()

Lorsque vous travaillez avec Camel, une route reçoit des paramètres, puis les convertit, les transforme et les traite. Après cela, il envoie ces paramètres à une autre route qui transfère le résultat à la sortie souhaitée (un fichier, une base de données, un serveur SMTP ou une réponse d'API REST).

Dans cet article, nous créons uniquement une autre route à l'intérieur de la méthodeconfigure() que nous surchargons. Ce sera la route de destination pour notre dernière routeto():

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));

La méthodefrom() suit les mêmes principes et possède plusieurs des mêmes méthodes que la méthoderest(), sauf qu'elle consomme des messages de contexte Camel. C'est la raison du paramètre «direct-route», qui crée un lien vers la méthoderest().to() précitée.

Many other conversions are available, y compris l'extraction en tant que primitives (ou objets) Java et leur envoi vers une couche de persistance. Notez que les itinéraires sont toujours lus à partir des messages entrants, de sorte que les itinéraires chaînés ignorent les messages sortants.

Notre exemple est prêt et nous pouvons l'essayer:

  • Exécutez la commande d'invite:mvn spring-boot:run

  • Faites une requête POST àhttp://localhost:8080/camel/api/bean avec les paramètres d'en-tête:Content-Type: application/json et une charge utile\{“id”: 1,”name”: “World”}

  • Nous devrions recevoir un code retour de 201 et la réponse:Hello, World

6.4. Le langage de script SIMPLE

L'exemple génère la journalisation à l'aide de la méthodetracing(). Notez que nous avons utilisé les espaces réservés$\{}; ceux-ci font partie d'un langage de script qui appartient à Camel appelé SIMPLE. Il s'applique aux messages échangés sur la route, comme le corps du message entrant.

Dans notre exemple, nous utilisons SIMPLE pour générer dans le journal les attributs de bean contenus dans le corps du message Camel.

Nous pouvons également l'utiliser pour faire des transformations simples, comme cela a été montré avec la méthodetransform().

6.5. Routefrom() avecprocess()

Faisons quelque chose de plus significatif, comme appeler une couche de service pour renvoyer les données traitées. SIMPLE n'est pas destiné au traitement intensif des données, remplaçons donc lestransform() par une méthodeprocess():

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));

Cela nous permet d'extraire les données dans un bean, le même que celui précédemment défini sur la méthodetype(), et de les traiter dans notre coucheExampleServices.

Puisque nous avons défini lesbindingMode() sur JSON précédemment, la réponse est déjà dans un format JSON approprié, généré sur la base de notre POJO. Cela implique que pour une classeExampleServices:

public class ExampleServices {
    public static void example(MyBean bodyIn) {
        bodyIn.setName( "Hello, " + bodyIn.getName() );
        bodyIn.setId(bodyIn.getId() * 10);
    }
}

La même requête HTTP retourne maintenant avec un code de réponse 201 et un corps:\{“id”: 10,”name”: “Hello, World”}.

7. Conclusion

Avec quelques lignes de code, nous avons réussi à créer une application relativement complète. Toutes les dépendances sont construites, gérées et exécutées automatiquement avec une seule commande. De plus, nous pouvons créer des API qui relient toutes sortes de technologies.

Cette approche est également très conviviale pour les conteneurs, ce qui crée un environnement de serveur très léger pouvant être facilement répliqué à la demande. Les possibilités de configuration supplémentaires peuvent facilement être incorporées dans un fichier de configuration de modèle de conteneur.

Cet exemple REST peut être trouvéover on GitHub.

Enfin, au-delà des APIfilter(),process(),transform() etmarshall(), de nombreux autres modèles d'intégration et manipulations de données sont disponibles dans Camel: