Vous avez déjà entendu parler d’Apache Camel ?
Les Design Pattern n’ont plus de secrets pour vous ?
L’Event Driven Architecture vous attire ?
Les Enterprise Integration Pattern vous interpellent ?
Vos applications reposent sur TCP, JMS, FTP, SFTP, les fichiers, les mails, XML, les web services SOAP, REST, RSS, JPA, JDBC ou même Twitter ?
N’attendez plus : venez découvrir l’utilisation des patterns comme le Channel Adapter, le Router ou l’Aggregator au travers d’un workshop sur Spring Integration.
Voici le support de présentation d’un workshop d’1h s’appuyant sur le cas d’étude suivant : un moteur chargé d’indexer des données clients dans le moteur de recherche Elasticsearch.
Une connaissance minimaliste de Spring Framework est pré-requise.
Spring Integration est à votre portée de main. EAI et ESB n’ont qu’à bien se tenir !!
Découvrez comment l’ECM peut concrètement « BOOSTER » votre entreprise à trav...
Workshop Spring - Session 5 - Spring Integration
1. Workshop Spring - Session 5
Etudes de cas
Spring Intégration
Diffusé en novembre 2013
Réactualisé en janvier 2015
2. Sommaire
Introduction à Spring Integration 3
Présentation de l’étude de cas 6
Implémentation avec Spring Integration 11
Conclusion 23
Workshop Spring Integration – Etude de Cas
2
3. Introduction
• Le messenging est une technique d’intégration entre
applications
– Souvent basé sur un Message Oriented Middleware (MoM)
• Permet 3 formes de Découplage :
• Spatial
• Temporel
• Logique
• Certains partisans poussent son Utilisation Au sein même
d’une même application
• Composants échangeant des données par messages en mémoire
• Applications orientées évènements
• Adaptateurs permettant de se connecter à des systèmes externes
3
Communication par messages
4. Introduction
• Livre cataloguant les patterns de type messaging utilisés
en entreprise pour architecturer le SI
– Ecrit par Gregor Hohpe et Bobby Woolf
• Standardisation de concepts MOM
• Liste de Patterns et iconographie
• Message
• Contient des En-têtes et un Contenu (Payload)
• Channel
• Point à Point ou de type Publish / Subscribe
• Envoi bloquant ou asynchrone
• Endpoint
• Connecte les Channels au code applicatif
et aux systèmes externes
4
Enterprise Integration Patterns (EIP)
5. Introduction
• Implémentation des Enteprise integration patterns
• Apache CAMEL en est une autre
• Repose sur le framework Spring et de
nombreux projets
• Reste un simple Framewok
• Offre de nombreux adapateurs :
• JMS
• JDBC, JPA, Mongo DB, REDIS
• HTTP, TCP / UDP
• Fichier, FTP, SFTP
• RSS, ATOM
• Mail, Twitter, XMPP, XML, Web services, RMI
5
Spring Intégration
6. Présentation de l’étude de cas
• Application de recherche et d’indexation
o Basée sur le moteur Elasticsearch
o Données métier issues de différents
référentiels et Back Office
• Indexation des données au fil de l’eau
o Mise en œuvre au sein d’une architecture SOA
o Exploitant l’infrastructure existante (ESB)
6
Application Indexo
7. Notification asynchrone envoyée à Indexo par JMS lors d’une création /
modification / suppression d’un ou plusieurs Produits
Consultation des données produits par appel d’un web service SOAP
Construction puis écriture du document à indexer dans Elasticsearch
7
Présentation de l’étude de cas
Communication entre applications
Serveur
Elasticsearch
Indexo
Module
d’indexation fil
de l’eau
Produx
Référentiel
Produits
ESB
JMS / XML
HTTP / SOAP
TCP / JSON
1
1
2
2
3
3
8. 8
A format XML, une notification est composée de 2 parties :
1. En-tête technique : standardisé par le framework de notification de l’ESB
2. Partie métier : spécifique à l’application Indexo
• Cartouche technique :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Notification xmlns="http://v1.event.esb.javaetmoi.com">
<Header>
<Label>Business Object Domain Changes</Label>
<SentTime>2015-01-12T21:10:30+02:00</SentTime>
<Version>1</Version>
<MessageNumber>1456098922309</MessageNumber>
<Origin>PRODUX</Origin>
<Type>BODC</Type>
</Header>
<Body>Notification métier</Body>
</Notification>
Utilisé par l’ESB:
• Filtrage
• Routage JMS
Contenu
au format XML
Présentation de l’étude de cas
Notifications (1/2)
9. • Partie Métier
• Contient les informations relatives à la modification d'un ou plusieurs
objets métiers
• Spécifiée par une XSD (au même titre que le cartouche technique)
9
Présentation de l’étude de cas
Notifications (2/2)
Propriété Type Description
action Enumération Action de création, de modification ou de
suppression d'un objet métier
actionDate Timestamp Date et heure à laquelle l'action a eu lieu
businessId String Identifiant métier de l'objet mis à jour
objectTypeCode String Contient le nom des objets métiers du
dictionnaire d'entreprise
10. 10
1. Lecture de la notification à partir de la file JMS
2. Filtrage à partir du cartouche technique
Permet d’écarter les notifications non destinées à Indexo
3. Traitement des erreurs
Fichier de logs et envoi de mails
4. Extraction puis unmarshalling XML de la partie métier
5. Séparation en informations de mise à jour unitaire
6. Routage en fonction de l’action
Le traitement des notifications de suppression est
transverse à tous les objets métiers
7. Routage en fonction du type d’objet métier
8. Récupération des données à indexer
Appel du ou des web services SOAP ou REST de consultation
9. Construction du document Lucene à indexer
10.Ecriture du document dans Elasticsearch
Présentation de l’étude de cas
Décomposition du traitement des notifications
11. Implémentation avec Spring Intégration
• Beans d’infrastructure du contexte applicatif Spring
• Connection Fatory JMS, File JMS (lookup JNDI ou standalone)
• Pools de threads (TaskExecutor)
• Marshaller JAXB 2 (Spring OXM)
• Clients Spring Web Services
• Client Elasticsearch
• Mise en œuvre basée sur Spring Integration 2.2.0
• Le JAR spring-integration-core + autant de jar que de technologies
supportées utilisées
• Configuration de Spring Integration
• Fichier de configuration XML avec espaces de nommage dédiés :
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-xml="http://www.springframework.org/schema/integration/xml"
• Annotations @MessageEndpoint, @Header, @Payload, @Gateway …
11
Mise en place de l’Architecture applicative
12. <!-- Fabrique de connexions JMS du broker de l’ESB -->
<jee:jndi-lookup id="jmsConnectionFactory" jndi-name="IndexoEventCF">
<jee:environment>
java.naming.factory.initial=xxx
java.naming.provider.url=yyy
</jee:environment>
</jee:jndi-lookup>
<task:executor id="businessChangeTaskExecutor"
pool-size="10-40"/>
<task:executor id="errorTaskExecutor"/>
<!-- Unmarshaller JAXB 2 de la partie métier de la notification -->
<oxm:jaxb2-marshaller id="businessEventUnmarshaller"
contextPath="com.javaetmoi.indexo.model.event.business.v1"/> 12
Définition des beans d’Infrastructure
Accès à l’annuaire JNDI
distant de l’ESB
Pools de threads dédiés à la
gestion des erreurs et aux
traitements de chaque objet
métier à indexer
Implémentation avec Spring Intégration
13. Implémentation avec Spring Intégration
• Utilisation du pattern Channel Adapter
• Connecte un channel avec des systèmes ou des services de transports externes
• 2 types de Channel Addapter : Inbound ou Outbound
• Uni-directionnel
• Implémentation retenue dans Spring Integration :
– Adapteur JMS entrant de type Message Driven
<int-jms:message-driven-channel-adapter
destination="EventQueue"
channel="jmsEventChanel" />
<int:channel id="jmsEventChanel" />
13
Etape 1 : Lecture de la notification à partir de la file JMS
Nom de la file JMS
en entrée d’Index
Channel dans lequel
le GenericMessage
est déposé
14. Implémentation avec Spring Intégration
• Utilisation du pattern Message Filter
• Décide de faire passer ou non un message vers le output
channel
• Par défaut : un message filtré est ignoré
• Autre configuration possible : levée d’une exception
ou message routé dans un discard-channel
• Implémentation retenue dans Spring Integration :
– Filtre XML par expression XPath
<int-xml:xpath-filter
input-channel="jmsEvenChannel"
output-channel="indexoEventChannel"
discard-channel="unexpectedEventChannel">
<int-xml:xpath-expression expression=
"/Notification/Header/Type = 'BODC'"/>
</int-xml:xpath-filter> 14
Etape 2 : Filtrage à partir du cartouche technique
Notification de type
BODC dédiée à Indexo
Notifications
invalides routées
dans un channel
15. Implémentation avec Spring Intégration
• Patterns Publish-Subscribe, Content Enricher et
Channel Adapter
– Génération d’un log d’erreur et envoi d’un email en
simultanés
<publish-subscribe-channel id="unknownEventChannel"
task-executor="errorTaskExecutor"/>
<logging-channel-adapter channel="unknownEventChannel" level="ERROR"
expression=« 'Unknown message: ' + payload.failedMesssage.payload"/>
<chain input-channel="unknownEventChannel"/>
<int-mail:header-enricher>
<int-mail:subject value="Unknown message"/>
<int-mail:to value="support@javaetmoi.com"/>
</int-mail:header-enricher>
<int-mail:outbound-channel-adapter host="mailserver" port="1021"/>
</chain>
15
Etape 3 : Traitement des erreurs
Non Bloquant
Abonnés appelés
en parallèle
Ajoute les en-
têtes mail_subject
et mail_to
16. Implémentation avec Spring Intégration
• Pattern de transformation de messages
– Seule la partie métier est nécessaire à l’indexation
– Utilisation du unmarshaller XML JAXB 2 proposé par
Spring OXM
• Implémentation basée sur le support XML de Spring
Intégration
<chain input-channel="indexoEventChannel"
output-channel="businessEventChannel"/>
<int-xml:xpath-transformer
xpath-expression="/Notification/Body"
evaluation-type="NODE_RESULT" />
<int-xml:unmarshalling-transformer
unmarshaller="businessEventUnmarshaller"/>
</chain> 16
Etape 4 : Extraction puis unmarshalling de la partie métier
17. Implémentation avec Spring Intégration
• Utilisation du pattern Message Splitter
• Découpe un message en plusieurs messages.
• Permet de segmenter le traitement d’un payload « composite » avec possibilité de
regroupement
• Implémentation avec chaque sous-message traité en parallèle :
public class BusinessDomainEventSplitter {
List<BusinessDomainChange> split(BusinessDomainEvent event) {
return event.getChanges();
} }
<context:bean id="businessDomainEventSplitter"
class="com...BusinessDomainEventSplitter"/>
<splitter input-channel="businessEventChannel"
output-channel="businessChangeChannel"
ref="businessDomainEventSplitter"/>
<channel id="businessChangeChannel">
<dispatcher task-executor="businessChangeTaskExecutor"/>
</channel>
17
Etape 5 : Séparation en informations de mise à jour unitaire
18. Implémentation avec Spring Intégration
• Utilisation du pattern Message Router
• Décide dynamiquement vers quel(s) channel(s) un message doit être
envoyé
• La décision est généralement fonction des en-têtes ou du contenu
• Implémentation à l’aide d’une Spring Expression Language (SpEL) :
<recipient-list-router input-channel="businessChangeChannel">
<recipient channel="objetUpdateChannel"
selector-expression="payload.action.equals(UPDATE)"/>
<recipient channel="objetDeleteChannel"
selector-expression="payload.action.equals(DELETE)"/>
</recipient-list-router>
• Configuration simplifiée :
<router input-channel="businessChangeChannel"
expression="'object' + payload.action + 'channel'" />
18
Etape 6 : Routage en fonction de l’action
19. Implémentation avec Spring Intégration
• Utilisation une 2nde fois du pattern Message Router
• Exemple de configuration par annotations :
<context:component-scan
base-package="com.javaetmoi.indexo.endpoint"/>
@MessageEndpoint
public class ModificationObjetMetierRouter {
@Router(inputChannel="objetUpdateChannel")
public String route(BusinessDomainChange payload) {
return payload.getObjetTypeCode() +"UpdateChannel";
}
}
19
Etape 7 : Routage en fonction du type d’objet métier
Nom de l’OuputChannel dans le cas d’une mise à jour
d’un produit : « productUpdateChannel »
Auto-détection des beans Spring
par analyse de package java
20. Implémentation avec Spring Intégration
• Utilisation du pattern Gateway
• Masque l’API de messaging de Spring Integration
• Une Outbound Gateway fait appel à un système externe et renvoie la réponse dans
l’application (sous forme de Message)
• Une Inbound Gateway fait rentrer des messages dans l’application et attend la réponse
• Implémentation à l’aide du support Web Services de SI :
– Fait appel au WS SOAP Produx de consultation d’un produit
<int-ws:outbound-gateway
request-channel="productUpdateChannel"
reply-channel="productDtoChannel"
destination-provider="wsProductClient"
marshaller="productMarshaller"
unmarshaller="productUnmarshaller"/>
20
Etape 8 : Récupération des données Poduits à indexer
Marshalling
manuel via
JDOM :
l’identifiant du
produit est
utilisé comme
paramètre
d’appel du WS
Le produit retourné par le WS est unmarshallé dans un
ProductDto via JAXB2
21. Implémentation avec Spring Intégration
• Utilisation du pattern Service Activator
• Endpoint générique connectant un service métier au système de messagerie de SI
• L’opération d’un service est invoquée pour traiter le message reçu sur l’input-channel
• La réponse est encapsulée dans un message émis sur le output-channel ou le replyChannel
@Service("productProcessorService")
public class ProcessorServiceImpl
implements ProductProcessorService {
@Override
public ProductDocument process(
DtoProduct product) { … }
}
<service-activator input-channel="productDtoChannel"
output-channel="productDocumentChannel"
ref="productProcessorService" method="process"/>
21
Etape 9 : Construction du document Lucene à indexer
Transforme les
données
produits en un
document
indexable par
Elasticsearch
22. Implémentation avec Spring Intégration
• Nouvelle utilisation du pattern Service Activator
@Service("productIndexWriterService")
public class ProductIndexWriterImpl
implements ProductIndexWriter {
@Autowired private Client esClient;
public void write(ProductDocument item) {
IndexRequestBuilder req = esClient
.prepareIndex(« indexo","product", item.getId());
req.setSource(ESContentBuilder.buildContent(item));
esClient.index(req);
} }
<service-activator input-channel="productDtoChannel"
ref="productIndexWriterService" method="write"/>
22
Etape 10 : Ecriture du document Dans Elasticsearch
23. Conclusion
• Plaisant malgré une phase d’apprentissage non négligeable
• Jeu de lego à l’aide de nombreuses briques
• Utilisation sur étagère
• Couplage Lâche facilitant les tests et la réutilisabilité
• Service métier réutilisé dans les batchs d’indexation
• Facilite la mise en place de modèles d’échanges asynchrones
orientés messages au sein d’une application basée sur Spring
• Simple paramétrage des channels
• Séparation des préoccupations entre la logique métier et la
logique d’intégration
• Spring Intégration Fourni la plomberie et des extensions pour les
connectivités
23
Bilan de l’étude de cas
24. Conclusion
• Polling de channels passifs
– Cadencement des traitements
• Failover et load-balancing
– Répartition de la charge induite par le traitement des messages et mode
dégradé
• Bridge
– Connecte 2 channels
• Intercepteurs
– Positionnés globalement ou sur chaque channel, pattern wire-tap
• Gestion des transactions
– Propagation du contexte transactionnel
• Message Store
– Persistance JMS ou base de données
• API de Construction des messages
– API fluent de construction de messages et de leurs en-têtes 24
Pour aller plus loin (1/2)
25. • Site et Manuel de référence de Spring Intégration
• http://www.springsource.org/spring-integration
• 331 pages, concepts, description détaillée, exemples complets
• Site de référence dess EIPS :
http://www.enterpriseintegrationpatterns.com
• Livres sur Spring Intégration
• Just Spring Integration
• Spring Integration in action
• Pro Spring Integration
• Code source sur Github
• Spring Tool Suite (STS)
• Modélisation Graphique
Conclusion
25
Pour aller plus loin (2/2)
Editor's Notes
Découplage
Spatial : les systèmes peuvent être distants ou non
Temporel : réponse non immédiatement attendue, interaction asynchrone, unidirectionnel ou bidirectionnel
Logique : l’émetteur n’a pas besoin de connaître le destinataire
Publié en 2003 => les concepts sont vieux (années 70)
Message : immuable, identifiant unique,
Analogie avec les messages JMS et SOAP ou les requêtes HTTP
En-têtes standardisées : durée de validité, adresse de retour, identifiant de corrélation
Channel : le canal où transitent tous les messages.
Endpoints : connecteurs, passif ou actifs (polling)
La version RC1 de Spring Integration est sortie fin 2008
Autres prohets : Spring Security, Spring Batch, Spring WS
API : <> conteneur / serveur, utilisable n’importe où : main(), web app, batch, swing …
Assimilable à un mini ESB
Extensions : projet Spring Integration Extension sur GitHub
1. Lecture de la notification à partir de la file JMS : l’ESB a préalablement validé le cartouche technique
Configuration possible à l’aide d’un DSL Groovy , Scala ou Java
Drivers du provider JMS à inclure dans le classpath
The result type expected from the XPath evaluation. This will be the type of the
header value. The following values are allowed: BOOLEAN_RESULT, STRING_RESULT,
NUMBER_RESULT, NODE_RESULT and NODE_LIST_RESULT. Defaults internally to
XPathEvaluationType.STRING_RESULT if not set. Optional.
Classe BusinessDomainEventSplitter : aucune d’adhérence avec Spring Intégration (annotations, interfaces), simple POJO
Gateway : fait office de proxy
Retour du service facultatif
Service métier utilisé par les batchs d’indexation
L’attribut method du service-activator est ici facultatif
Un changement de paramétrage peut avoir des effets de bord qu’il faut avoir à l’esprit (ex : parallélisme entrainant la perte du contexte de sécurité et du contexte transactionnel)