Spring对Java企业开发的影响是巨大的,从2004年发布到现在,一直都是Java开发主要的框架,随处可见Spring的身影。我读的Spring源码不多,但不代表我对她理解的不深刻。大众熟知Struts,Hibernate其实我都一知半解,还是上学的时候听“大虾”们说的他们很厉害才学了一些,现在已经放下了好几年了。我喜欢Spring的风格和架构,也是我开发的利器。Spring发展到现在有很多的子项目,如:Spring Batch,Spring Data Redis,Spring Data Neo4j, Spring Data Hadoop, Spring Security等。哦,还有Spring Integration。
如你所见,Integration,集成!也是Spring集大成者。我是这么认为的。
Sping Integration的介绍见:http://blog.csdn.net/slivefox/article/details/3740541
Spring Integration本身并不做任何事,它通过更高层次的抽象把各种技术杂合到一起,组成一个无缝的系统。如果你熟悉UML,你就懂得抽象在软件工程的重要性。
说了这么多,Spring Integration适合做什么?如果你的系统处在各个系统的中间,需要JMS交互,又需要Database/Redis/MongoDB,还需要监听Tcp/UDP等,还有固定的文件转移,分析。还面对着时不时的更改需求的风险。那么,它再适合不过了。
在Spring Integration中,Message是它的基础构件和核心,所有的流程都围绕着Message运转。如:
![](http://static.oschina.net/uploads/space/2012/1101/205446_fVFT_259382.png)
payload是他可以携带的任何Object对象,Header是她包含的一些头信息。如发mail时就需要,from,to,cc等信息。正文是一段text或者html可以存储在payload中。Message总是由外部系统触发而产生,我们称他为消息生产者Producer。这也很像事件驱动模型。如:
![](http://static.oschina.net/uploads/space/2012/1101/205525_wvI6_259382.png)
每个Message交互的时候都需要channel。从一个channel进入,从另一个channel流出。同时另一个channel又是下一个系统的流入端。如:
他们都通过一个适配器,把Message导向每一个需要的地方,而不伤害结构。也就是说如果更改了一个地方,我们只需要更改一个适配器。
我通过一个jms做一个简单的示例。
一个简单的Bean
public class JmsMessageBean implements Serializable {
private String name = null;
private Integer age = null;
private Date birthday = null;
private List<String> manbers = null;
//...getter and setter
}
一个MessageHandler:
public class JmsMessageCustomerHandler implements MessageHandler {
public JmsMessageCustomerHandler() {
}
@Override
public void handleMessage(Message<?> message) throws MessagingException {
//输出.
Object obj = message.getPayload();
if(obj == null) {
System.out.println("null");
} else if(obj instanceof String) {
System.out.println(obj);
} else if(obj instanceof JmsMessageBean) {
JmsMessageBean bean = (JmsMessageBean)obj;
System.out.println(ReflectionToStringBuilder.reflectionToString(bean));
} else {
System.out.println(ReflectionToStringBuilder.reflectionToString(message));
}
}
}
一个消息的中转,因为我不是把消息传递给下一个系统,我只是把它简单的输出。
public class JmsMessageCustomerTransformer implements Transformer {
public JmsMessageCustomerTransformer() {
}
@Override
public Message<?> transform(Message<?> message) {
//不做任何事,原样返回
return message;
}
}
Spring schema:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:integration="http://www.springframework.org/schema/integration"
xmlns:jms="http://www.springframework.org/schema/integration/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms-2.1.xsd">
<!-- jms 连接工厂 -->
<bean id="activeMQJmsFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>tcp://localhost:61616</value>
</property>
</bean>
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="activeMQJmsFactory" />
<property name="sessionCacheSize" value="10"/>
<property name="cacheProducers" value="false"/>
</bean>
<!-- jms Topic -->
<bean id="myTopic" class="org.apache.activemq.command.ActiveMQTopic"
autowire="constructor">
<constructor-arg value="jmstopic" />
</bean>
<bean id="messageConverter" class="net.dintegration.jms.JmsMessageConverter" />
<bean id="messageHander" class="net.dintegration.handler.JmsMessageCustomerHandler" />
<bean id="messageTransformer" class="net.dintegration.transformer.JmsMessageCustomerTransformer" />
<!-- jms 模板 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="defaultDestination" ref="myTopic" />
<property name="messageConverter" ref="messageConverter" />
</bean>
<integration:channel id="jmsinchannel"/>
<integration:channel id="jmsoutchannel" />
<jms:inbound-channel-adapter id="jmsIn" destination="myTopic" channel="jmsinchannel" jms-template="jmsTemplate">
<integration:poller fixed-rate="30000"/>
</jms:inbound-channel-adapter>
<integration:transformer ref="messageTransformer"
input-channel="jmsinchannel" output-channel="jmsoutchannel" />
<integration:service-activator ref="messageHander" input-channel="jmsoutchannel" />
</beans>
测试类:
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("jmsintegration/jmsIntSubscribeContext.xml");
context.start();
System.out.println("Please type something and hit return");
}
我在本机开启了一个ActiveMQ,上述测试类运行了之后线程会阻塞,JDK不会退出。使之接收JMS消息。
我另写了一个测试类发送了一条消息。如:
@Test
public void testSendJmsMessage() throws Exception {
System.out.println("=============================================");
JmsMessageBean bean = new JmsMessageBean();
bean.setAge(23);
bean.setBirthday(new Date());
bean.setManbers(Arrays.asList("123", "234", "345"));
bean.setName("Jms");
publisher.sendMessage(bean);
}
接收消息如下:
net.dintegration.jms.JmsMessageBean@49c54f01[name=Jms,age=23,birthday=Thu Nov 01 20:19:35 CST 2012,manbers=[123, 234, 345]] |
有人会问:这些代码是不是太罗嗦了?自己实现一个spring-jms都不会这么麻烦。
不知道你看到没有这样的代码:
<integration:channel id="jmsinchannel"/>
<integration:channel id="jmsoutchannel" />
<jms:inbound-channel-adapter id="jmsIn" destination="myTopic" channel="jmsinchannel" jms-template="jmsTemplate">
<integration:poller fixed-rate="30000"/>
</jms:inbound-channel-adapter>
<integration:transformer ref="messageTransformer"
input-channel="jmsinchannel" output-channel="jmsoutchannel" />
<integration:service-activator ref="messageHander" input-channel="jmsoutchannel" />
inbound-channel-adapter是在把一个jms的输入源绑定到 jmsinchannel上, transformer使用这个输入源转给 jmsoutchannel, jmsoutchannel又是下一个消费者的输入源。假如增加了从文件系统读取文件到jmsoutchannel呢?或者还有Tcp获得的数据到jmsoutchannel呢?因为inbound-channel-adapter可以把任何输入绑定到jmsinchannel。
你觉得呢?