1.简介
Spring Integration 4.0终于发布了 ,并且此版本具有非常好的功能。 本文介绍的一种可能性是完全不使用XML即可配置集成流程。 那些不喜欢XML的人仅使用JavaConfig就可以开发集成应用程序。
本文分为以下几节:
- 介绍。
- 流程概述。
- 弹簧配置。
- 端点的详细信息。
- 测试整个流程。
- 结论。
- 源代码可以在github上找到。
- 在此示例中调用的Web服务的源代码可以在github的spring-samples存储库中找到。
2.流程概述
该示例应用程序显示了如何配置多个消息传递和集成端点。 用户通过指定课程ID来请求课程。 该流程将调用Web服务,并将响应返回给用户。 此外,某些类型的课程将存储到数据库中。
流程如下:
- 集成网关 (课程服务)用作消息传递系统的入口。
- 转换器根据用户指定的课程ID生成请求消息。
- Web服务出站网关将请求发送到Web服务并等待响应。
- 服务激活器订阅了响应通道,以便将课程名称返回给用户。
- 过滤器也订阅了响应通道。 此过滤器会将某些类型的课程发送到mongodb 通道适配器 ,以便将响应存储到数据库。
下图更好地显示了流程的结构:
3.弹簧配置
如简介部分所述,整个配置是使用JavaConfig定义的。 此配置分为三个文件:基础结构,Web服务和数据库配置。 让我们来看看:
3.1基础架构配置
该配置文件仅包含消息通道的定义。 消息传递端点(变压器,过滤器等)配置有注释。
InfrastructureConfiguration.java
@Configuration
@ComponentScan("xpadro.spring.integration.endpoint") //@Component
@IntegrationComponentScan("xpadro.spring.integration.gateway") //@MessagingGateway
@EnableIntegration
@Import({MongoDBConfiguration.class, WebServiceConfiguration.class})
public class InfrastructureConfiguration {
@Bean
@Description("Entry to the messaging system through the gateway.")
public MessageChannel requestChannel() {
return new DirectChannel();
}
@Bean
@Description("Sends request messages to the web service outbound gateway")
public MessageChannel invocationChannel() {
return new DirectChannel();
}
@Bean
@Description("Sends web service responses to both the client and a database")
public MessageChannel responseChannel() {
return new PublishSubscribeChannel();
}
@Bean
@Description("Stores non filtered messages to the database")
public MessageChannel storeChannel() {
return new DirectChannel();
}
}
@ComponentScan注释搜索@Component注释的类,它们是我们定义的消息传递终结点; 过滤器,变压器和服务激活器。
@IntegrationComponentScan批注搜索特定的集成批注。 在我们的示例中,它将扫描用@MessagingGateway注释的入口网关。
@EnableIntegration批注启用集成配置。 例如,方法级别的注释,例如@Transformer或@Filter。
3.2 Web服务配置
此配置文件配置Web服务出站网关及其必需的编组器。
WebServiceConfiguration.java
@Configuration
public class WebServiceConfiguration {
@Bean
@ServiceActivator(inputChannel = "invocationChannel")
public MessageHandler wsOutboundGateway() {
MarshallingWebServiceOutboundGateway gw = new MarshallingWebServiceOutboundGateway("http://localhost:8080/spring-ws-courses/courses", jaxb2Marshaller());
gw.setOutputChannelName("responseChannel");
return gw;
}
@Bean
public Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("xpadro.spring.integration.ws.types");
return marshaller;
}
}
网关允许我们定义其输出通道,但不能定义输入通道。 我们需要使用@ServiceActivator注释适配器,以便将其订阅到调用通道,并避免必须在消息通道Bean定义中自动装配适配器。
3.3数据库配置
该配置文件定义了设置mongoDB所需的所有必需bean。 它还定义了mongoDB出站通道适配器。
MongoDBConfiguration.java
@Configuration
public class MongoDBConfiguration {
@Bean
public MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new MongoClient(), "si4Db");
}
@Bean
@ServiceActivator(inputChannel = "storeChannel")
public MessageHandler mongodbAdapter() throws Exception {
MongoDbStoringMessageHandler adapter = new MongoDbStoringMessageHandler(mongoDbFactory());
adapter.setCollectionNameExpression(new LiteralExpression("courses"));
return adapter;
}
}
像Web服务网关一样,我们无法将输入通道设置为适配器。 我还通过在@ServiceActivator批注中指定输入通道来完成此操作。
4.端点的细节
流的第一个端点是集成网关,它将把参数(courseId)放入消息的有效负载中并将其发送到请求通道。
@MessagingGateway(name = "entryGateway", defaultRequestChannel = "requestChannel")
public interface CourseService {
public String findCourse(String courseId);
}
包含课程ID的消息将到达转换器。 该端点将构建Web服务期望的请求对象:
@Component
public class CourseRequestBuilder {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Transformer(inputChannel="requestChannel", outputChannel="invocationChannel")
public GetCourseRequest buildRequest(Message<String> msg) {
logger.info("Building request for course [{}]", msg.getPayload());
GetCourseRequest request = new GetCourseRequest();
request.setCourseId(msg.getPayload());
return request;
}
}
订阅了响应通道,这是将发送Web服务回复的通道,有一个服务激活器将接收响应消息并将课程名称传递给客户端:
@Component
public class CourseResponseHandler {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@ServiceActivator(inputChannel="responseChannel")
public String getResponse(Message<GetCourseResponse> msg) {
GetCourseResponse course = msg.getPayload();
logger.info("Course with ID [{}] received: {}", course.getCourseId(), course.getName());
return course.getName();
}
}
同样需要订阅响应通道的过滤器,将根据其类型决定是否将课程存储到数据库:
@Component
public class StoredCoursesFilter {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Filter(inputChannel="responseChannel", outputChannel="storeChannel")
public boolean filterCourse(Message<GetCourseResponse> msg) {
if (!msg.getPayload().getCourseId().startsWith("BC-")) {
logger.info("Course [{}] filtered. Not a BF course", msg.getPayload().getCourseId());
return false;
}
logger.info("Course [{}] validated. Storing to database", msg.getPayload().getCourseId());
return true;
}
}
5.测试整个流程
以下客户端将发送两个请求; BC类型的课程请求将被存储到数据库中,而DF类型的课程将被最终过滤:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={InfrastructureConfiguration.class})
public class TestApp {
@Autowired
CourseService service;
@Test
public void testFlow() {
String courseName = service.findCourse("BC-45");
assertNotNull(courseName);
assertEquals("Introduction to Java", courseName);
courseName = service.findCourse("DF-21");
assertNotNull(courseName);
assertEquals("Functional Programming Principles in Scala", courseName);
}
}
这将导致以下控制台输出:
CourseRequestBuilder|Building request for course [BC-45]
CourseResponseHandler|Course with ID [BC-45] received: Introduction to Java
StoredCoursesFilter|Course [BC-45] validated. Storing to database
CourseRequestBuilder|Building request for course [DF-21]
CourseResponseHandler|Course with ID [DF-21] received: Functional Programming Principles in Scala
StoredCoursesFilter|Course [DF-21] filtered. Not a BF course
六,结论
我们已经学习了如何在不使用XML配置的情况下设置和测试支持Spring Integration的应用程序。 请继续关注,因为带有Spring Integration 扩展的 Spring Integration Java DSL即将推出!
翻译自: https://www.javacodegeeks.com/2014/05/spring-integration-4-0-a-complete-xml-free-example.html