diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java index 2f9d51bd25e..186f9811f78 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java @@ -55,6 +55,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; +import org.springframework.context.annotation.Lazy; import org.springframework.context.expression.EnvironmentAccessor; import org.springframework.context.expression.MapAccessor; import org.springframework.core.convert.converter.Converter; @@ -65,6 +66,7 @@ import org.springframework.integration.annotation.Aggregator; import org.springframework.integration.annotation.BridgeFrom; import org.springframework.integration.annotation.BridgeTo; +import org.springframework.integration.annotation.EndpointId; import org.springframework.integration.annotation.Gateway; import org.springframework.integration.annotation.GatewayHeader; import org.springframework.integration.annotation.InboundChannelAdapter; @@ -94,6 +96,7 @@ import org.springframework.integration.core.MessagingTemplate; import org.springframework.integration.core.Pausable; import org.springframework.integration.endpoint.AbstractEndpoint; +import org.springframework.integration.endpoint.EventDrivenConsumer; import org.springframework.integration.endpoint.MethodInvokingMessageSource; import org.springframework.integration.endpoint.PollingConsumer; import org.springframework.integration.expression.SpelPropertyAccessorRegistrar; @@ -149,6 +152,9 @@ public class EnableIntegrationTests { @Autowired private ApplicationContext context; + @Autowired + private ContextConfiguration2 contextConfiguration2; + @Autowired private PollableChannel input; @@ -284,6 +290,10 @@ public class EnableIntegrationTests { @Autowired private PublisherAnnotationBeanPostProcessor publisherAnnotationBeanPostProcessor; + @Autowired + @Qualifier("controlBusEndpoint") + private EventDrivenConsumer controlBusEndpoint; + @Test public void testAnnotatedServiceActivator() throws Exception { this.serviceActivatorEndpoint.start(); @@ -427,6 +437,12 @@ public void testAnnotatedServiceActivator() throws Exception { assertThat(beansOfType.keySet() .contains("enableIntegrationTests.ContextConfiguration2.controlBus.serviceActivator.handler")) .isFalse(); + + assertThat(this.controlBusEndpoint.getBeanName()) + .isEqualTo(this.contextConfiguration2.controlBusEndpoint.getBeanName()); + + assertThat(this.controlBusEndpoint.getHandler()) + .isSameAs(this.contextConfiguration2.controlBusEndpoint.getHandler()); } @Test @@ -1065,13 +1081,19 @@ public MessageHandler sendAsyncHandler() { @Bean @ServiceActivator(inputChannel = "controlBusChannel") + @EndpointId("controlBusEndpoint") @Role("bar") public ExpressionControlBusFactoryBean controlBus() { return new ExpressionControlBusFactoryBean(); } + @Autowired + @Qualifier("controlBusEndpoint") + @Lazy + private EventDrivenConsumer controlBusEndpoint; + @Bean - public Pausable pausable() { + public Pausable pausable(@Qualifier("controlBusChannel") @Lazy MessageChannel controlBusChannel) { return new Pausable() { private volatile boolean running; diff --git a/src/reference/asciidoc/configuration.adoc b/src/reference/asciidoc/configuration.adoc index 0dd26c2d228..32c31823c49 100644 --- a/src/reference/asciidoc/configuration.adoc +++ b/src/reference/asciidoc/configuration.adoc @@ -315,8 +315,7 @@ public class ThingService { ==== NOTE: The value of the annotation can also be a SpEL expression (for example, `someHeader.toUpperCase()`), which is useful when you wish to manipulate the header value before injecting it. -It also provides an optional `required` property, which specifies whether the attribute value must be available within -the headers. +It also provides an optional `required` property, which specifies whether the attribute value must be available within the headers. The default value for the `required` property is `true`. For several of these annotations, when a message-handling method returns a non-null value, the endpoint tries to send a reply. @@ -345,8 +344,9 @@ public class ThingService { The processing of these annotations creates the same beans as the corresponding XML components -- `AbstractEndpoint` instances and `MessageHandler` instances (or `MessageSource` instances for the inbound channel adapter). See <>. -The bean names are generated from the following pattern: `[componentName].[methodName].[decapitalizedAnnotationClassShortName]` -(for example, for the preceding example the bean name is `thingService.otherThing.serviceActivator`) for the `AbstractEndpoint` and the same name with an additional `.handler` (`.source`) suffix for the `MessageHandler` (`MessageSource`) bean. +The bean names are generated from the following pattern: `[componentName].[methodName].[decapitalizedAnnotationClassShortName]`. +In the preceding example the bean name is `thingService.otherThing.serviceActivator` for the `AbstractEndpoint` and the same name with an additional `.handler` (`.source`) suffix for the `MessageHandler` (`MessageSource`) bean. +Such a name can be customized using an `@EndpointId` annotation alongside with these messaging annotations. The `MessageHandler` instances (`MessageSource` instances) are also eligible to be tracked by <<./message-history.adoc#message-history,the message history>>. Starting with version 4.0, all messaging annotations provide `SmartLifecycle` options (`autoStartup` and `phase`) to allow endpoint lifecycle control on application context initialization. @@ -355,6 +355,28 @@ To change the state of an endpoint (such as ` start()` or `stop()`), you can obt Alternatively, you can send a command message to the `Control Bus` (see <<./control-bus.adoc#control-bus,Control Bus>>). For these purposes, you should use the `beanName` mentioned earlier in the preceding paragraph. +[IMPORTANT] +===== +Channels automatically created after parsing the mentioned annotations (when no specific channel bean is configured), and the corresponding consumer endpoints, are declared as beans near the end of the context initialization. +These beans **can** be autowired in other services, but they have to be marked with the `@Lazy` annotation because the definitions, typically, won't yet be available during normal autowiring processing. + +==== +[source, java] +---- +@Autowired +@Lazy +@Qualifier("someChannel") +MessageChannel someChannel; +... + +@Bean +Thing1 dependsOnSPCA(@Qualifier("someInboundAdapter") @Lazy SourcePollingChannelAdapter someInboundAdapter) { + ... +} +---- +==== +===== + [[configuration-using-poller-annotation]] ==== Using the `@Poller` Annotation diff --git a/src/reference/asciidoc/overview.adoc b/src/reference/asciidoc/overview.adoc index fc166533298..d8f6dc11552 100644 --- a/src/reference/asciidoc/overview.adoc +++ b/src/reference/asciidoc/overview.adoc @@ -136,8 +136,7 @@ The chapters that follow elaborate and provide sample code as well as configurat ==== Message Transformer A message transformer is responsible for converting a message's content or structure and returning the modified message. -Probably the most common type of transformer is one that converts the payload of the message from one format to another (such as -from XML to `java.lang.String`). +Probably the most common type of transformer is one that converts the payload of the message from one format to another (such as from XML to `java.lang.String`). Similarly, a transformer can add, remove, or modify the message's header values. [[overview-endpoints-filter]] @@ -213,7 +212,7 @@ Spring Integration provides a number of channel adapters, which are described in .An inbound channel adapter endpoint connects a source system to a `MessageChannel`. image::images/source-endpoint.jpg[align="center", scaledwidth=100%] -NOTE: Message sources can be pollable (for example, POP3) or message-driven_ (for example, IMAP Idle). +NOTE: Message sources can be pollable (for example, POP3) or message-driven (for example, IMAP Idle). In the preceding diagram, this is depicted by the "`clock`" symbol and the solid arrow (poll) and the dotted arrow (message-driven). .An outbound channel adapter endpoint connects a `MessageChannel` to a target system. @@ -294,7 +293,7 @@ Consider the following example of an annotated bean: ==== [source, java] ---- -@Configuratiom +@Configuration public class SomeConfiguration { @Bean @@ -317,7 +316,7 @@ Starting with version 5.0.4, you can modify these names by using the `@EndpointI ==== [source, java] ---- -@Configuratiom +@Configuration public class SomeConfiguration { @Bean("someService.handler") <1> @@ -405,13 +404,10 @@ For example, many endpoints consist of a `MessageHandler` bean and a `ConsumerEn The first time a Spring Integration namespace element is encountered, the framework automatically declares a number of beans (a task scheduler, an implicit channel creator, and others) that are used to support the runtime environment. -IMPORTANT: Version 4.0 introduced the `@EnableIntegration` annotation, to allow the -registration of Spring Integration infrastructure beans (see the -https://docs.spring.io/spring-integration/docs/latest-ga/api/org/springframework/integration/config/EnableIntegration.html[Javadoc]). +IMPORTANT: Version 4.0 introduced the `@EnableIntegration` annotation, to allow the registration of Spring Integration infrastructure beans (see the https://docs.spring.io/spring-integration/docs/latest-ga/api/org/springframework/integration/config/EnableIntegration.html[Javadoc]). This annotation is required when only Java configuration is used -- for example with Spring Boot or Spring Integration Messaging Annotation support and Spring Integration Java DSL with no XML integration configuration. -The `@EnableIntegration` annotation is also useful when you have a parent context with no Spring Integration components -and two or more child contexts that use Spring Integration. +The `@EnableIntegration` annotation is also useful when you have a parent context with no Spring Integration components and two or more child contexts that use Spring Integration. It lets these common components be declared once only, in the parent context. The `@EnableIntegration` annotation registers many infrastructure components with the application context. @@ -605,8 +601,7 @@ Its main implementations are: When you use messaging annotations or the Java DSL, you need to worry about these components, because the Framework automatically produces them with appropriate annotations and `BeanPostProcessor` implementations. When building components manually, you should use the `ConsumerEndpointFactoryBean` to help determine the target `AbstractEndpoint` consumer implementation to create, based on the provided `inputChannel` property. -On the other hand, the `ConsumerEndpointFactoryBean` delegates to an another first class citizen in the Framework: -`org.springframework.messaging.MessageHandler`. +On the other hand, the `ConsumerEndpointFactoryBean` delegates to an another first class citizen in the Framework - `org.springframework.messaging.MessageHandler`. The goal of the implementation of this interface is to handle the message consumed by the endpoint from the channel. All EIP components in Spring Integration are `MessageHandler` implementations (for example, `AggregatingMessageHandler`, `MessageTransformingHandler`, `AbstractMessageSplitter`, and others). The target protocol outbound adapters (`FileWritingMessageHandler`, `HttpRequestExecutingMessageHandler`, `AbstractMqttMessageHandler`, and others) are also `MessageHandler` implementations.