ENTERPRISE INTEGRATION PATTERNS: 
SPRING WAY 
Dragan Gajic
INTEGRATION 
• Creating a single, monolite app to cover 
all aspects of business is hard 
• Enterpises are comprised of 
applications which can be: custom 
build, 3rd party, legacy 
• Connecting computer systems, 
companies or people 
• Share data and processes
INTEGRATION CHALLENGES 
• Networks: unreliable & slow 
• Differences: language, platform & data format 
• Changes 
• Limited control 
• Standards 
• Maintenance
INTEGRATION STYLES 
• File transfer 
• Shared DB 
• RMI 
• Messaging 
• asyncronous 
• reliable transfer 
• common format (messages) 
• Loose coupling
MESSAGE AND CHANNEL 
• Message 
• Header – information about the data 
• Payload (body) – the data being transmitted 
• Channel 
Header 
Payload 
Header 
Payload 
• Point-to-Point 
• Publish-Subscribe 
Header 
Payload 
Header 
Payload 
Header 
Payload 
Producer Consumer
PIPES AND FILTERS 
Persist 
Pipe 
Create validation 
email 
Pipe Pipe 
Filter Filter 
Send validation 
email 
SMTP 
Pipe 
Filter 
USER 
Registration 
• Divide complex processing 
• Filters – independent processing steps 
• Pipes – connect filters into a sequence 
• Fundamental architectural style for messaging 
• Pipe = Channel 
• Filter = Endpoint
SPRING INTEGRATION 
• Top-level project in spring.io 
• Enables lightweight messaging 
• Combines DI, POJO and Messaging 
• Implements most of EIP 
• Includes wide selection of channel adapters 
• SI != MOM, ESB
EXAMPLE: USER REGISTRATION 
• After user registration validate email address by sending 
confirmation link to email and notify moderators about new 
profile 
• In steps: 
• Generate confirmation link (UUID) 
• Store userId -> UUID 
• Send confirmation email 
• Notify site moderators about the new profile 
SMTP 
ADMIN 
REST API
CHANNEL ADAPTER 
@RequestMapping(method = RequestMethod.POST) 
@ResponseStatus(HttpStatus.CREATED) 
public ProfileResource register(@Valid @RequestBody RegistrationResource registration) { 
Profile profile = profileService.save(regResToProfile.convert(registration)); 
publisher.publishEvent(new RegistrationEvent(this, profile)); 
return profileToProfileResource.convert(profile); 
} 
<int-event:inbound-channel-adapter channel="event-channel" 
event-types=“x.x.RegistrationEvent"/> 
<channel id="event-channel“ />
ENRICHER 
<header-enricher input-channel="event-channel"> 
<header name="uuid“ expression="T(java.util.UUID).randomUUID.toString()"/> 
</header-enricher>
WIRE-TAP 
<wire-tap channel="logger"/>
PIPING IT ALL TOGETHER 
<int-event:inbound-channel-adapter channel="event-channel" 
event-types="com.levi9.samples.eip.registration.event.RegistrationEvent" /> 
<channel id="event-channel" /> 
<header-enricher input-channel="event-channel" output-channel=“logger"> 
<header name="uuid" expression="T(java.util.UUID).randomUUID().toString()" /> 
</header-enricher> 
<logging-channel-adapter id="logger" level="INFO" log-full-message="true" />
COMPOSITE PROCESSOR
SPLITTER & ROUTER 
<splitter input-channel="confirmation-channel“ output-channel="splitted" method="split"> 
<beans:bean class="com.levi9.samples.eip.registration.splitter.ProfileSplitter" /> 
</splitter> 
<payload-type-router input-channel="splitted"> 
<mapping type="java.lang.Long" channel="save" /> 
<mapping type="com.levi9.samples.eip.registration.model.Profile" channel=“email" /> 
</payload-type-router> 
public Object[] split(RegistrationEvent event) { 
Profile profile = event.getProfile(); 
return new Object[] {profile.getId(), profile}; 
}
<service-activator input-channel="save" output-channel="done" 
expression="@profileService.pending(headers.uuid, payload)" /> 
<chain input-channel="email" output-channel="done"> 
<int-mail:header-enricher> 
<int-mail:from value="EIP" /> 
<int-mail:to expression="payload.email" /> 
<int-mail:subject value="Registration confirmation" /> 
</int-mail:header-enricher> 
<transformer 
expression="'Dear ' + payload.name + ', please click on the following link 
#{ environment['host.name'] }/confirm/' + headers.uuid 
+ ' in order to confirm email address.'" /> 
</chain> 
SERVICE ACTIVATOR & TRANSLATOR 
public boolean pending(String uuid, Long id) { 
return confirmations.put(uuid, id) == null; 
}
AGGREGATOR & MAIL ADAPTER 
public String aggregate(List<Message<?>> messages) { 
return (String) messages 
.stream() 
.filter(p -> p.getPayload() instanceof String) 
.findFirst().orElse(null).getPayload(); 
} 
<aggregator input-channel="done" method="aggregate" message-store=“store" 
output-channel="mail-outbound" > 
<bean class="com.levi9.samples.eip.registration.aggregator.ConfirmationAggregator"/> 
</aggregator> 
<channel id="mail-outbound" /> 
<int-mail:outbound-channel-adapter channel="mail-outbound" 
host="#{ environment['mail.smtp.host']}" 
port="#{ environment['mail.smtp.port']}" /> 
<bean id=“store" class="org.springframework.integration.store.SimpleMessageStore" />
MESSAGING SYSTEM 
message 
SMTP 
ADMIN 
REST API
DEMO 
https://gitlab.levi9.com/d.gajic/eip/tree/code3
RESOURCES 
• Book 
• Enterprise Integration Patterns 
• Gregor Hohpe, Bobby Woolf 
• Spring Integration 
• http://projects.spring.io/spring-integration 
• Samples 
• https://gitlab.levi9.com/d.gajic/eip.git 
• Patterns 
• http://www.enterpriseintegrationpatterns.com
Q&A

Enterprise Integration Patterns - Spring way

  • 1.
    ENTERPRISE INTEGRATION PATTERNS: SPRING WAY Dragan Gajic
  • 2.
    INTEGRATION • Creatinga single, monolite app to cover all aspects of business is hard • Enterpises are comprised of applications which can be: custom build, 3rd party, legacy • Connecting computer systems, companies or people • Share data and processes
  • 3.
    INTEGRATION CHALLENGES •Networks: unreliable & slow • Differences: language, platform & data format • Changes • Limited control • Standards • Maintenance
  • 4.
    INTEGRATION STYLES •File transfer • Shared DB • RMI • Messaging • asyncronous • reliable transfer • common format (messages) • Loose coupling
  • 5.
    MESSAGE AND CHANNEL • Message • Header – information about the data • Payload (body) – the data being transmitted • Channel Header Payload Header Payload • Point-to-Point • Publish-Subscribe Header Payload Header Payload Header Payload Producer Consumer
  • 6.
    PIPES AND FILTERS Persist Pipe Create validation email Pipe Pipe Filter Filter Send validation email SMTP Pipe Filter USER Registration • Divide complex processing • Filters – independent processing steps • Pipes – connect filters into a sequence • Fundamental architectural style for messaging • Pipe = Channel • Filter = Endpoint
  • 7.
    SPRING INTEGRATION •Top-level project in spring.io • Enables lightweight messaging • Combines DI, POJO and Messaging • Implements most of EIP • Includes wide selection of channel adapters • SI != MOM, ESB
  • 8.
    EXAMPLE: USER REGISTRATION • After user registration validate email address by sending confirmation link to email and notify moderators about new profile • In steps: • Generate confirmation link (UUID) • Store userId -> UUID • Send confirmation email • Notify site moderators about the new profile SMTP ADMIN REST API
  • 9.
    CHANNEL ADAPTER @RequestMapping(method= RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public ProfileResource register(@Valid @RequestBody RegistrationResource registration) { Profile profile = profileService.save(regResToProfile.convert(registration)); publisher.publishEvent(new RegistrationEvent(this, profile)); return profileToProfileResource.convert(profile); } <int-event:inbound-channel-adapter channel="event-channel" event-types=“x.x.RegistrationEvent"/> <channel id="event-channel“ />
  • 10.
    ENRICHER <header-enricher input-channel="event-channel"> <header name="uuid“ expression="T(java.util.UUID).randomUUID.toString()"/> </header-enricher>
  • 11.
  • 12.
    PIPING IT ALLTOGETHER <int-event:inbound-channel-adapter channel="event-channel" event-types="com.levi9.samples.eip.registration.event.RegistrationEvent" /> <channel id="event-channel" /> <header-enricher input-channel="event-channel" output-channel=“logger"> <header name="uuid" expression="T(java.util.UUID).randomUUID().toString()" /> </header-enricher> <logging-channel-adapter id="logger" level="INFO" log-full-message="true" />
  • 13.
  • 14.
    SPLITTER & ROUTER <splitter input-channel="confirmation-channel“ output-channel="splitted" method="split"> <beans:bean class="com.levi9.samples.eip.registration.splitter.ProfileSplitter" /> </splitter> <payload-type-router input-channel="splitted"> <mapping type="java.lang.Long" channel="save" /> <mapping type="com.levi9.samples.eip.registration.model.Profile" channel=“email" /> </payload-type-router> public Object[] split(RegistrationEvent event) { Profile profile = event.getProfile(); return new Object[] {profile.getId(), profile}; }
  • 15.
    <service-activator input-channel="save" output-channel="done" expression="@profileService.pending(headers.uuid, payload)" /> <chain input-channel="email" output-channel="done"> <int-mail:header-enricher> <int-mail:from value="EIP" /> <int-mail:to expression="payload.email" /> <int-mail:subject value="Registration confirmation" /> </int-mail:header-enricher> <transformer expression="'Dear ' + payload.name + ', please click on the following link #{ environment['host.name'] }/confirm/' + headers.uuid + ' in order to confirm email address.'" /> </chain> SERVICE ACTIVATOR & TRANSLATOR public boolean pending(String uuid, Long id) { return confirmations.put(uuid, id) == null; }
  • 16.
    AGGREGATOR & MAILADAPTER public String aggregate(List<Message<?>> messages) { return (String) messages .stream() .filter(p -> p.getPayload() instanceof String) .findFirst().orElse(null).getPayload(); } <aggregator input-channel="done" method="aggregate" message-store=“store" output-channel="mail-outbound" > <bean class="com.levi9.samples.eip.registration.aggregator.ConfirmationAggregator"/> </aggregator> <channel id="mail-outbound" /> <int-mail:outbound-channel-adapter channel="mail-outbound" host="#{ environment['mail.smtp.host']}" port="#{ environment['mail.smtp.port']}" /> <bean id=“store" class="org.springframework.integration.store.SimpleMessageStore" />
  • 17.
    MESSAGING SYSTEM message SMTP ADMIN REST API
  • 18.
  • 19.
    RESOURCES • Book • Enterprise Integration Patterns • Gregor Hohpe, Bobby Woolf • Spring Integration • http://projects.spring.io/spring-integration • Samples • https://gitlab.levi9.com/d.gajic/eip.git • Patterns • http://www.enterpriseintegrationpatterns.com
  • 20.

Editor's Notes

  • #3 Information Portal Data Replication Shared Business Function SOA Distributed Business Process B2B Integration
  • #4 Data transport over network compared to the same on one computer requires taking into account much more things which can go wrong. This is because networks are generally unreliable and slow, which requires more complex implementations of data transport in order to achieve reliability not compromising performance. Changes: unavoidable Limited control: 3rd party or legacy Standards: XML – no semantics Maintenance: operation and maintenance (infrastructure automation)
  • #5 File: formats, frequency, transfer, sync issues (sharing data) DB: SQL RBDMS (standard) + ORM, schema issues (and relational model is not suitable for all use cases – NoSQL + NO encapsulation) (sharing data) RMI: encapsulation (Java RMI, WS SOAP), performance (local vs remote calls) (sharing functions) Messaging: Loose coupling: sender no longer has to depend on receiver internal data format (messages) nor its location (channels) or readiness (asynchronous + queuing)
  • #6 Message – data encapsulation Channel – decouples message producers from consumers Point-to-Point: only one receiver will consume particular message; channel CAN have multiple consumers Publish-Subscribe: broadcast any message to all subscribers
  • #7 Message – data encapsulation Channel – decouples message producers from consumers Routers – multiple outputs (location independency) Transformers: convert messages Endpoints: adapters
  • #10 Inbound Channel Adapter: connect an application to the messaging system so that it can send and receive messages (Spring application events in this case) Direct Channel: point to point semantics Message: payload = RegistrationEvent
  • #11 Content Enricher: appends data to the message – headers and/or payload (use expression to generate UUID and add to the message header)
  • #12 Wire Tap: publishes each incoming message to the main channel and a secondary channel (per channel or global)
  • #13 Inbound Channel Adapter: connect an application to the messaging system so that it can send and receive messages (Spring application events in this case) Content Enricher: appends data to the message – headers and/or payload (use expression to generate UUID and add to the message header) Wire Tap: publishes each incoming message to the main channel and a secondary channel (per channel or global)
  • #14 Composite processor: splits the message up, routes the sub messages to appropriate destinations and aggregates responses (harder because of the asynchronous nature).
  • #15 Composite processor: splits the message up, routes the sub messages to appropriate destinations and aggregates responses (harder because of the asynchronous nature).
  • #16 Composite processor: splits the message up, routes the sub messages to appropriate destinations and aggregates responses (harder because of the asynchronous nature).
  • #17 Composite processor: splits the message up, routes the sub messages to appropriate destinations and aggregates responses (harder because of the asynchronous nature).
  • #18 Publisher-Subscriber: multiple consumers AMQP (RabbitMQ): inbound/outbound channel adapters
  • #19 Publisher-Subscriber: multiple consumers AMQP (RabbitMQ): inbound/outbound channel adapters
  • #20 File: DB: RMI: Messaging: