消息元注解
从 4.0 版本开始,所有消息注解都可以配置为元注解,并且所有用户定义的消息注解都可以定义相同的属性来覆盖其默认值。此外,元注解可以分层配置,如下例所示:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ServiceActivator(inputChannel = "annInput", outputChannel = "annOutput")
public @interface MyServiceActivator {
String[] adviceChain = { "annAdvice" };
}
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@MyServiceActivator
public @interface MyServiceActivator1 {
String inputChannel();
String outputChannel();
}
...
@MyServiceActivator1(inputChannel = "inputChannel", outputChannel = "outputChannel")
public Object service(Object payload) {
...
}
通过分层配置元注解,用户可以设置各种属性的默认值,并将框架的Java依赖隔离到用户自定义的注解中,避免在用户类中直接使用这些依赖。如果框架发现某个方法带有用户自定义的注解,并且该注解又包含了框架的元注解,那么该方法将被视为直接使用了框架注解。
@Bean 方法的注解
从版本 4.0 开始,你可以在 @Configuration 类中的 @Bean 方法定义上配置消息注解,以基于 bean 而非方法生成消息端点。当 @Bean 定义是现成的 MessageHandler 实例(如 AggregatingMessageHandler、DefaultMessageSplitter 等)、Transformer 实例(如 JsonToObjectTransformer、ClaimCheckOutTransformer 等)以及 MessageSource 实例(如 FileReadingMessageSource、RedisStoreMessageSource 等)时,这非常有用。以下示例展示了如何将消息注解与 @Bean 注解结合使用:
@Configuration
@EnableIntegration
public class MyFlowConfiguration {
@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public MessageSource<String> consoleSource() {
return CharacterStreamReadingMessageSource.stdin();
}
@Bean
@Transformer(inputChannel = "inputChannel", outputChannel = "httpChannel")
public ObjectToMapTransformer toMapTransformer() {
return new ObjectToMapTransformer();
}
@Bean
@ServiceActivator(inputChannel = "httpChannel")
public HttpRequestExecutingMessageHandler httpHandler() {
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("https://foo/service");
handler.setExpectedResponseType(String.class);
handler.setOutputChannelName("outputChannel");
return handler;
}
@Bean
@ServiceActivator(inputChannel = "outputChannel")
public LoggingHandler loggingHandler() {
return new LoggingHandler("info");
}
}
版本 5.0 引入了对带有 @InboundChannelAdapter 注解的 @Bean 的支持,该注解可返回 java.util.function.Supplier,该函数能够生成 POJO 或 Message。以下示例展示了如何使用这种组合:
@Configuration
@EnableIntegration
public class MyFlowConfiguration {
@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public Supplier<String> pojoSupplier() {
return () -> "foo";
}
@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public Supplier<Message<String>> messageSupplier() {
return () -> new GenericMessage<>("foo");
}
}
元注解规则同样适用于 @Bean 方法(前文介绍的 @MyServiceActivator 注解也可应用于 @Bean 定义)。
当你在消费者 @Bean 定义上使用这些注解时,如果 bean 定义返回一个合适的 MessageHandler(取决于注解类型),你必须在 MessageHandler 的 @Bean 定义本身上设置属性(例如 outputChannel、requiresReply、order 等)。只有以下注解属性会被使用:adviceChain、autoStartup、inputChannel、phase 和 poller。所有其他属性都是针对处理器的。
Bean 名称的生成遵循以下算法:
-
MessageHandler(MessageSource) 的@Bean会从方法名或@Bean上的name属性获取其自身的标准名称。这就像@Bean方法上没有消息注解一样工作。 -
AbstractEndpoint的 bean 名称按以下模式生成:[@Bean 名称].[首字母小写的注解类短名]。例如,前面所示 的consoleSource()定义的SourcePollingChannelAdapter端点会获得一个名为consoleSource.inboundChannelAdapter的 bean 名称。与 POJO 方法不同,bean 方法名称不包含在端点 bean 名称中。另请参阅 端点 Bean 名称。 -
如果
@Bean不能直接在目标端点中使用(不是MessageSource、AbstractReplyProducingMessageHandler或AbstractMessageRouter的实例),则会注册一个相应的AbstractStandardMessageHandlerFactoryBean来委托给这个@Bean。此包装器的 bean 名称按以下模式生成:[@Bean 名称].[首字母小写的注解类短名].[handler (或 source)]。
在 @Bean 定义上使用这些注解时,inputChannel 必须引用一个已声明的 bean。如果应用上下文中尚未存在通道,则会自动声明它们。
在 Java 配置中,你可以在 @Bean 方法级别使用任何 @Conditional(例如 @Profile)定义,以在某些条件原因下跳过 bean 的注册。以下示例展示了如何实现:
@Bean
@ServiceActivator(inputChannel = "skippedChannel")
@Profile("thing")
public MessageHandler skipped() {
return System.out::println;
}
结合现有的 Spring 容器逻辑,基于 @ServiceActivator 注解的消息端点 bean 也不会被注册。
使用注解创建桥接
从版本 4.0 开始,Java 配置提供了 @BridgeFrom 和 @BridgeTo @Bean 方法注解,用于在 @Configuration 类中标记 MessageChannel bean。这些注解的存在是为了实现完整性,提供了一种便捷的机制来声明 BridgeHandler 及其消息端点配置:
@Bean
public PollableChannel bridgeFromInput() {
return new QueueChannel();
}
@Bean
@BridgeFrom(value = "bridgeFromInput", poller = @Poller(fixedDelay = "1000"))
public MessageChannel bridgeFromOutput() {
return new DirectChannel();
}
@Bean
public QueueChannel bridgeToOutput() {
return new QueueChannel();
}
@Bean
@BridgeTo("bridgeToOutput")
public MessageChannel bridgeToInput() {
return new DirectChannel();
}
你也可以将这些注解用作元注解。
建议注解端点
请参阅使用注解通知端点。