Let's imagine a simple flow:
Modelling it is not that difficult. Here's our MessageRouter class:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MessageRouter { | |
private XMLHandler xmlHandler = new XMLHandler(); | |
private JSONHandler jsonHandler = new JSONHandler(); | |
public void route(String message) { | |
if (message.startsWith("<?xml")) { | |
xmlHandler.process(message); | |
} else { | |
jsonHandler.process(message); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class XMLHandler { | |
private Persister persister = new Persister(); | |
public void process(String message) { | |
System.out.println("Processing xml message: " + message); | |
persister.persist(message); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class JSONHandler { | |
private Persister persister = new Persister(); | |
public void process(String message) { | |
System.out.println("Processing json message: " + message); | |
persister.persist(message); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Persister { | |
public void persist(String message) { | |
System.out.println("persisting " + message); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class App { | |
public static void main(String[] args) { | |
MessageRouter router = new MessageRouter(); | |
router.route("{'json'}"); | |
router.route("<?xml/>"); | |
} | |
} |
Message router knows about handlers and handlers know about persister.
We would gain loose coupling and high cohesion if they weren't aware of each other which would automatically make them concentrate on one task only.
Spring Integration can help us achieve this.
It is a separate module of Spring, enabling lightweight messaging within application and supporting Enterprise Integration Patterns.
All the arrows from the above picture will be represented as channels.
The XML Spring context configuration for the channels looks pretty straightforward:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<int:channel id="messageChannel"/> | |
<int:channel id="XMLChannel"/> | |
<int:channel id="JSONChannel"/> | |
<int:channel id="persisterChannel"/> |
Apart from the channels, our MessageRouter only role is to return the channel name to which the message will be passed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Component | |
public class MessageRouter { | |
@Router | |
public String route(String message) { | |
return message.startsWith("<?xml") ? "XMLChannel" : "JSONChannel"; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Component | |
public class JSONHandler { | |
@ServiceActivator | |
public String process(String message) { | |
System.out.println("Processing json message: " + message); | |
return message; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Component | |
public class XMLHandler { | |
@ServiceActivator | |
public String process(String message) { | |
System.out.println("Processing xml message: " + message); | |
return message; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Component | |
public class Persister { | |
@ServiceActivator | |
public void persist(String message) { | |
System.out.println("persisting " + message); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<int:router input-channel="messageChannel" ref="messageRouter"/> | |
<int:service-activator input-channel="XMLChannel" output-channel="persisterChannel" ref="XMLHandler"/> | |
<int:service-activator input-channel="JSONChannel" output-channel="persisterChannel" ref="JSONHandler"/> | |
<int:service-activator input-channel="persisterChannel" ref="persister"/> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class App { | |
public static void main(String[] args) { | |
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml"); | |
MessageChannel channel = context.getBean("messageChannel", MessageChannel.class); | |
channel.send(MessageBuilder.withPayload("{'json'}").build()); | |
channel.send(MessageBuilder.withPayload("<?xml/>").build()); | |
} | |
} |
The components do not depend on each other.
What is more, if we wanted to modify the flow and move Persister component in front of the MessageRouter, we would need to change the xml config to:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<int:service-activator input-channel="XMLChannel" output-channel="nullChannel" ref="XMLHandler"/> | |
<int:service-activator input-channel="JSONChannel" output-channel="nullChannel" ref="JSONHandler"/> | |
<int:service-activator input-channel="persisterChannel" output-channel="messageChannel" ref="persister"/> |
Nevertheless we increased the complexity of our application. Now we depend on a framework and we need to maintain additional configuration in an XML file.
Another big disadvantage is testing. We could easily unit test the previous code using mocks. Now we need to test the Java code and Spring Integration configuration as well, which is not that simple.
I'll show how to do it in the next post.