1.简介

Spring Integration 4.0终于发布了 ,并且此版本具有非常好的功能。 本文介绍的一种可能性是完全不使用XML即可配置集成流程。 那些不喜欢XML的人仅使用JavaConfig就可以开发集成应用程序。

本文分为以下几节:

  1. 介绍。
  2. 流程概述。
  3. 弹簧配置。
  4. 端点的详细信息。
  5. 测试整个流程。
  6. 结论。
  • 源代码可以在github上找到。
  • 在此示例中调用的Web服务的源代码可以在github的spring-samples存储库中找到。

2.流程概述

该示例应用程序显示了如何配置多个消息传递和集成端点。 用户通过指定课程ID来请求课程。 该流程将调用Web服务,并将响应返回给用户。 此外,某些类型的课程将存储到数据库中。

流程如下:

  • 集成网关 (课程服务)用作消息传递系统的入口。
  • 转换器根据用户指定的课程ID生成请求消息。
  • Web服务出站网关将请求发送到Web服务并等待响应。
  • 服务激活器订阅了响应通道,以便将课程名称返回给用户。
  • 过滤器也订阅了响应通道。 此过滤器会将某些类型的课程发送到mongodb 通道适配器 ,以便将响应存储到数据库。

下图更好地显示了流程的结构: springclod支持tcp和udp spring integration tcp_java

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