美文网首页
Spring integration part2.5 Getti

Spring integration part2.5 Getti

作者: 吉祥如意酥 | 来源:发表于2018-01-25 22:07 被阅读0次

在之前的文章简单讨论了channel,message,大概了解了几种endpoint,通过一些简单的配置分析,大概能够串联一些简单的流程。在这一章,会讨论transformer以及相关的一些endpoint,对一些流程更加熟悉。

Domain-driven transformation

现在是面向对象的时代,类作为信息的模版又可以被看作是数据的模型,对象则是承载数据的载体。但是相较于用对象在系统间传递信息,使用类文本的结构能够更方便的进行信息的传递,尤其是对于Spring integration这种用message作为载体的设计,比如Xml。那么必要的一点就是如何在整个流程的头尾进行Domain和xml信息的转换。这个流程可以简单表述为:Domain object -marshallinh-> portable format(xml)-unmarshalling-> domain object。使中间的处理流程使用方便处理的信息进行传递。另外顺便说一句,xml是很典型的这类数据,不光是因为它本身结构简单,而且可以通过xslt文件或者xpath语句对其进行解读和处理,十分的方便。另外,可能出现其他的格式需求,比如json,csv等等,当然如果每一种格式之间都有transformer就会很混乱,所以其实比较好的是用xml格式作为中介,每一种格式只需要实现fromXml和ToXml就可以了,减少了复杂度。

下面我们来解析一段配置并且介绍一些知识点:

<channel id="delayEvents"><queue/></channel>

<transformer input-channel ="flightDelayInput" ref="flightEventTransformer"

method="convertToDelayEvent" output-channel="delayEvents"/>

<context:component-scan base-package="siia.business"/>

<beans:bean class="siia.business.StubFlightScheduler"/>

这一段配置和上一章有些许不同,首先,“flightDelayInput”这个channel并没有配置(并不是我懒得打)如果没有配置,那么Input channel会默默地自己生成。另外下面的context:component-scan 和bean和Spring的上配置有关,这里没有附着代码部分,但是在代码里面有一些@注释,各有各的意思,其中@Messagepont @Autowired 和bean配置完成了依赖注入,就是在都配置文件的时候创建依赖的对象并注入,而不用在代码里面“create”。具体的知识请参考Spring的相关知识。

另外,我们在前几张说过两个关键词:解耦和易测。每一个Transformer都可以有其自己的Unit Test。用到了Junit的相关知识。确保每一个transformer,以及其他Endpoint能够保证本身的可测性及质量。

Transformer不单单包括类型间的转换,还可以对header和payload进行处理。

第一种就是Content enricher,它的应用场景是对payload的内容进行处理,比如判断,合并和处理之类的。(当然如果是xml信息,使用xslt也能处理类似的情况)第二种是Header enricher,因为Adapter或者Gateway相比于Payload更关注header的信息,甚至发送的邮件地址都需要从Payload中组装而成,这个时候就需要从payload中提取所需要的信息并且整理塞进header中,以便后续使用。对于发邮件的这个情况Spring 3.0还支持一种更简单的通过配置实现的方式:

<mail:header-enricher><mail:to expression="payload?.profile?.emailAddress"/></mail:header-enricher>

这里的?是一种对payload和profile的判断。当然这种方法的缺点一个是测试的实现一个是不易读。所以并不是简单的就是最好的。

Message-driven services

上一部分介绍了消息进来何处去时候的第一或最后一步就是通过transformer进行转换,在消息处理过程中呢,一般使用service activator这个component。先举一个例子:

<service-activator input-channel="flightDelays" output-channel="statusUpdates" ref="flightStatusService" method="updateStatus"/>

<beans:bean id="flightStatusService" class="siia.business.SimpleFlightStatusService"/>

在之前章节简单介绍过这种component,两个进出的channel,相关的类和方法。bean是将siia.business.SimpleFlightStatusService的对象注入到类flightStatusService中。

我们考虑一种情况,就是一个service activator或者是其他的双向的components,如果在调用的方法中存在返回值,但是没有配置output-channel会怎样。这里还有一种解决方式就是在header中配置output-channel(当然这也是在处理过程中进行的,如下)。

Message requestMessage = MessageBuilder.withPayload(someObject).setReplyChannel(replyChannelObject).build().

值得注意的是,如果一个Service有返回值,但是既没有声明output-channel,在message header中也没有replyChannel,将会抛出Runtime exception。

Message publishing interceptors

消息拦截器,可以理解为一个新的对流程的事件触发机制。应用场景可以理解为,当一个状态发生改变的时候,使所有相关的事物发生改变。听起来象是一个Publisher信息发布者。上文涉及到Spring框架实现依赖注入的配置,这里用到则是另外一点,AOP面向切面。就是这个拦截器并不存在于整个流程中,而是设定在一个特定的时机,可以理解为切面进行触发。实现方式如如下代码:

public class SimpleFlightStatusService implements FlightStatusService{

@Publisher(channel="statisticsChannel")

public FlightStatus updateStatus(@Payload FlightDelayEvent flightDelayEvent)

//更新DB中Status的数据 //其它相关操作

return new FlightStatus();}

可以看出通过两个注解,实现了设置触发条件(channel="statisticsChannel")和获取payload,文件内容的效果。

Domain-drive Messaging Gateways

Gateway相当于设计模式的门面模式,使得用户不需要直接跟Spring Integration的api交互,只需要跟自己定义的接口做交互就行了。用户的业务代码中不需要耦合进spring integration框架的代码。也就是说之前我们需要通过Spring Integration的api获取Channel,并且向它发送message。而使用Gateway之后只需要知道我调用了一个Service,而他自己会shengchengmessage并发送到default channel中。

举一个例子:

public class FlightStatusNotificationPublisher{

private MailSender mailSender;

private JmsTemplate jmsTemplate;

public FlightStatusNotificationPublisher(MailSender mailSender,JmsTemplate jmsTemplate){

this.mailSender = mailSender;

this.jmsTemplate = jmsTemplate;

}

public void publishNotification(FlightStatusEvent event){

SimpleMailMessage mailMessage = null;//create maile Message

this.mailSender.send(mailMessage);

this,jmsTemplate.convertAndSend(event);

}}

这个类就是将要暴露的接口,在配置中将会配置Email和JMS的相关信息,当调用publishNotification的时候,message就会发出。

配置如下:

<gateway defult-request-channel="flightStatusNotifications" service-interface="siia.business.FlightStatusNotificationPublisher"/><!--声明接口和默认端口-->

<object-to-string-transformer input-channel="flightStatusNotifications" output-channel="flightStatusStrings"/><!--将对象转化为String-->

<publish-subscribe-channel id="flightStatusStrings"/><!--订阅式的channel,可以触发所有连接该channel的endpoint-->

<mail:outbound-channel-adapter channel="flightStatusStrings" mail-sender="mailSender"><!--Mail Sender的配置 Outbound Adapter-->

<jms:outbound-channel-adapter channel="flightStatusStrings" destination="flightStatusQueue"/><!--JMS Sender配置 Outbound Adapter-->

可以看出通过以上配置可以实现我们之前说到的功能。

Chaining endpoints

是不是有的时候觉得配置channel比较烦,因为虽然他没有实现什么,但是每两个Endpoint之间就要有一个channel。那么,有一种情况我们可以不配置这些channel,就是很多endpoint处于连续,单流程(无分支)的情况,可以理解为整个流程可以在一个transaction之内完成,那么我们能将这样的一段flow称之并配置成一个chain,配置如下:

<chain input-channel="passengers">

<transformer ref="passengerProfileEnricher" method="addProfileInAvailable"/>

<mail:header-enricher><mail:to expression="payload?.profile?.emailAddress"/></mailheader-enricher>

<transformer ref="flightDelayEmailGenerator" method="generateEmail"/>

<mail:outbound-channel-adapter mail-sender="mailSender"/>

</chain>

这一段配置就将transformer,email-richer,transformer,email-sender串在了一起,省去了很多配置。并且这样写最大的好处就是一眼能够看出这是一个整体,一串流程,更易读。

小结

这一部分我们介绍了比较常用的component,transformer。然后我们还了解了一些在Spring Integration中的注解,AOP思想。接触了消息拦截器,发布器和Gatway。知道了如何对单独的模块进行testcase的编码。还学习到了非常有用且易用的chain结构。通过一些简单的配置和示例能够更容易的体会其中的用法。接下来我们还会探索更多有用的endpoint或者其他结构。

相关文章

网友评论

      本文标题:Spring integration part2.5 Getti

      本文链接:https://www.haomeiwen.com/subject/ghbraxtx.html