Skip to content

Commit

Permalink
GH-3111: Document @lazy for messaging annotations (#3142)
Browse files Browse the repository at this point in the history
* GH-3111: Document @lazy for messaging annotations

Fixes #3111
Fixes #3130

* Fix some typos in docs
* Ensure in tests that announced `@Lazy` works as expected

* Doc Polishing

Co-authored-by: Gary Russell <grussell@pivotal.io>
  • Loading branch information
artembilan and garyrussell committed Jan 15, 2020
1 parent f93a740 commit 442c4fa
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 17 deletions.
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -149,6 +152,9 @@ public class EnableIntegrationTests {
@Autowired
private ApplicationContext context;

@Autowired
private ContextConfiguration2 contextConfiguration2;

@Autowired
private PollableChannel input;

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
30 changes: 26 additions & 4 deletions src/reference/asciidoc/configuration.adoc
Expand Up @@ -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.
Expand Down Expand Up @@ -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 <<annotations_on_beans>>.
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.
Expand All @@ -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

Expand Down
19 changes: 7 additions & 12 deletions src/reference/asciidoc/overview.adoc
Expand Up @@ -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]]
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -294,7 +293,7 @@ Consider the following example of an annotated bean:
====
[source, java]
----
@Configuratiom
@Configuration
public class SomeConfiguration {
@Bean
Expand All @@ -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>
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 442c4fa

Please sign in to comment.