Skip to content

Commit 69af967

Browse files
artembilangaryrussell
authored andcommitted
INT-4488: Require @EnablePublisher
JIRA: https://jira.spring.io/browse/INT-4488 Since `PublisherAnnotationBeanPostProcessor` is quite expensive (1.5x the CPU used by `MessagingAnnotationPostProcessor` in a simple application) * So not register a `PublisherAnnotationBeanPostProcessor` by default. The `@EnablePublisher` has to be presented on the `@Configuration` to allow the `@Publisher` AOP * Change the `<int:annotation-config>` to require a new `<int:enable-publisher>` sub-element for similar purpose - do not register `PublisherAnnotationBeanPostProcessor` by default
1 parent 13510df commit 69af967

File tree

9 files changed

+118
-60
lines changed

9 files changed

+118
-60
lines changed

spring-integration-core/src/main/java/org/springframework/integration/config/EnablePublisher.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,12 +27,10 @@
2727
/**
2828
* Provides the registration for the {@link org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor}
2929
* to allow the use of the {@link org.springframework.integration.annotation.Publisher} annotation.
30-
* In addition the {@code default-publisher-channel} name has to be configured as the {@code value} of this annotation.
31-
* <p>
32-
* Note: the {@link org.springframework.integration.annotation.Publisher} annotation is enabled by default via
33-
* {@link EnableIntegration} processing, but there is no hook to configure the {@code default-publisher-channel}.
30+
* In addition the {@code default-publisher-channel} name can be configured as the {@code value} of this annotation.
3431
*
3532
* @author Artem Bilan
33+
*
3634
* @since 4.0
3735
*/
3836
@Target(ElementType.TYPE)
@@ -44,5 +42,5 @@
4442
/**
4543
* @return the {@code default-publisher-channel} name.
4644
*/
47-
String value();
45+
String value() default "";
4846
}

spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,15 +391,20 @@ private void registerMessagingAnnotationPostProcessors(AnnotationMetadata meta,
391391
builder.getBeanDefinition());
392392
}
393393

394-
new PublisherRegistrar().registerBeanDefinitions(meta, registry);
394+
if (meta.getAnnotationAttributes(EnablePublisher.class.getName()) != null) {
395+
new PublisherRegistrar().
396+
registerBeanDefinitions(meta, registry);
397+
}
395398
}
396399

397400
/**
398401
* Register {@link IntegrationConfigurationBeanFactoryPostProcessor}
399402
* to process the external Integration infrastructure.
400403
*/
401404
private void registerIntegrationConfigurationBeanFactoryPostProcessor(BeanDefinitionRegistry registry) {
402-
if (!registry.containsBeanDefinition(IntegrationContextUtils.INTEGRATION_CONFIGURATION_POST_PROCESSOR_BEAN_NAME)) {
405+
if (!registry.containsBeanDefinition(
406+
IntegrationContextUtils.INTEGRATION_CONFIGURATION_POST_PROCESSOR_BEAN_NAME)) {
407+
403408
BeanDefinitionBuilder postProcessorBuilder = BeanDefinitionBuilder
404409
.genericBeanDefinition(IntegrationConfigurationBeanFactoryPostProcessor.class)
405410
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AnnotationConfigParser.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,7 +25,9 @@
2525
import org.springframework.beans.factory.xml.BeanDefinitionParser;
2626
import org.springframework.beans.factory.xml.ParserContext;
2727
import org.springframework.core.type.StandardAnnotationMetadata;
28+
import org.springframework.integration.config.EnablePublisher;
2829
import org.springframework.integration.config.IntegrationRegistrar;
30+
import org.springframework.util.xml.DomUtils;
2931

3032
/**
3133
* Parser for the &lt;annotation-config&gt; element of the integration namespace.
@@ -38,13 +40,33 @@ public class AnnotationConfigParser implements BeanDefinitionParser {
3840

3941
@Override
4042
public BeanDefinition parse(final Element element, ParserContext parserContext) {
41-
new IntegrationRegistrar().registerBeanDefinitions(new StandardAnnotationMetadata(Object.class) {
43+
IntegrationRegistrar integrationRegistrar = new IntegrationRegistrar();
44+
integrationRegistrar.setBeanClassLoader(parserContext.getReaderContext().getBeanClassLoader());
4245

43-
@Override
44-
public Map<String, Object> getAnnotationAttributes(String annotationType) {
45-
return Collections.<String, Object>singletonMap("value", element.getAttribute("default-publisher-channel"));
46-
}
47-
}, parserContext.getRegistry());
46+
StandardAnnotationMetadata importingClassMetadata =
47+
new StandardAnnotationMetadata(Object.class) {
48+
49+
@Override
50+
public Map<String, Object> getAnnotationAttributes(String annotationType) {
51+
if (EnablePublisher.class.getName().equals(annotationType)) {
52+
Element enablePublisherElement =
53+
DomUtils.getChildElementByTagName(element, "enable-publisher");
54+
if (enablePublisherElement != null) {
55+
return Collections.singletonMap("value",
56+
enablePublisherElement.getAttribute("default-publisher-channel"));
57+
}
58+
else {
59+
return null;
60+
}
61+
}
62+
else {
63+
return null;
64+
}
65+
}
66+
67+
};
68+
69+
integrationRegistrar.registerBeanDefinitions(importingClassMetadata, parserContext.getRegistry());
4870

4971
return null;
5072
}

spring-integration-core/src/main/resources/org/springframework/integration/config/spring-integration-5.1.xsd

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,24 @@
2020
</xsd:documentation>
2121
</xsd:annotation>
2222
<xsd:complexType>
23-
<xsd:attribute name="default-publisher-channel" type="xsd:string" use="optional">
24-
<xsd:annotation>
25-
<xsd:documentation>
26-
Default output channel for the @Publisher annotation support.
27-
</xsd:documentation>
28-
<xsd:appinfo>
29-
<tool:annotation kind="ref">
30-
<tool:expected-type type="org.springframework.messaging.MessageChannel" />
31-
</tool:annotation>
32-
</xsd:appinfo>
33-
</xsd:annotation>
34-
</xsd:attribute>
23+
<xsd:sequence>
24+
<xsd:element name="enable-publisher" minOccurs="0">
25+
<xsd:complexType>
26+
<xsd:attribute name="default-publisher-channel" type="xsd:string">
27+
<xsd:annotation>
28+
<xsd:documentation>
29+
Default output channel for the @Publisher annotation support.
30+
</xsd:documentation>
31+
<xsd:appinfo>
32+
<tool:annotation kind="ref">
33+
<tool:expected-type type="org.springframework.messaging.MessageChannel" />
34+
</tool:annotation>
35+
</xsd:appinfo>
36+
</xsd:annotation>
37+
</xsd:attribute>
38+
</xsd:complexType>
39+
</xsd:element>
40+
</xsd:sequence>
3541
</xsd:complexType>
3642
</xsd:element>
3743

@@ -53,22 +59,22 @@
5359
</xsd:annotation>
5460
<xsd:complexType>
5561
<xsd:sequence>
56-
<xsd:element name="before-commit" minOccurs="0" maxOccurs="1">
57-
<xsd:complexType>
58-
<xsd:attributeGroup ref="synchronizationAttributeGroup"/>
59-
</xsd:complexType>
60-
</xsd:element>
61-
<xsd:element name="after-commit" minOccurs="0" maxOccurs="1">
62-
<xsd:complexType>
63-
<xsd:attributeGroup ref="synchronizationAttributeGroup"/>
64-
</xsd:complexType>
65-
</xsd:element>
66-
<xsd:element name="after-rollback" minOccurs="0" maxOccurs="1">
67-
<xsd:complexType>
68-
<xsd:attributeGroup ref="synchronizationAttributeGroup"/>
69-
</xsd:complexType>
70-
</xsd:element>
71-
</xsd:sequence>
62+
<xsd:element name="before-commit" minOccurs="0" maxOccurs="1">
63+
<xsd:complexType>
64+
<xsd:attributeGroup ref="synchronizationAttributeGroup"/>
65+
</xsd:complexType>
66+
</xsd:element>
67+
<xsd:element name="after-commit" minOccurs="0" maxOccurs="1">
68+
<xsd:complexType>
69+
<xsd:attributeGroup ref="synchronizationAttributeGroup"/>
70+
</xsd:complexType>
71+
</xsd:element>
72+
<xsd:element name="after-rollback" minOccurs="0" maxOccurs="1">
73+
<xsd:complexType>
74+
<xsd:attributeGroup ref="synchronizationAttributeGroup"/>
75+
</xsd:complexType>
76+
</xsd:element>
77+
</xsd:sequence>
7278
<xsd:attribute name="id" type="xsd:string" use="required"/>
7379
</xsd:complexType>
7480
</xsd:element>
@@ -134,7 +140,7 @@
134140
<xsd:annotation>
135141
<xsd:documentation>
136142
Defines a Point-to-Point MessageChannel.
137-
See 'PointToPointChannelParser' source code for 'MessageChannel' implementaitons.
143+
See 'PointToPointChannelParser' source code for 'MessageChannel' implementations.
138144
</xsd:documentation>
139145
<xsd:appinfo>
140146
<tool:annotation>

spring-integration-core/src/test/java/org/springframework/integration/aggregator/BarrierMessageHandlerTests.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.springframework.integration.channel.DirectChannel;
5656
import org.springframework.integration.channel.QueueChannel;
5757
import org.springframework.integration.config.EnableIntegration;
58+
import org.springframework.integration.config.EnablePublisher;
5859
import org.springframework.integration.handler.ReplyRequiredException;
5960
import org.springframework.integration.support.MessageBuilder;
6061
import org.springframework.integration.test.util.TestUtils;
@@ -72,6 +73,7 @@
7273
/**
7374
* @author Gary Russell
7475
* @author Artem Bilan
76+
*
7577
* @since 4.2
7678
*
7779
*/
@@ -263,6 +265,7 @@ public void testJavaConfig() {
263265

264266
@Configuration
265267
@EnableIntegration
268+
@EnablePublisher
266269
public static class Config {
267270

268271
@Bean

spring-integration-core/src/test/java/org/springframework/integration/aop/AnnotationConfigRegistrationTests-context.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<beans xmlns="http://www.springframework.org/schema/beans"
33
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xmlns:aop="http://www.springframework.org/schema/aop"
5-
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
6-
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
4+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
75
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"
86
xmlns:si="http://www.springframework.org/schema/integration">
97

@@ -17,6 +15,8 @@
1715
<si:queue />
1816
</si:channel>
1917

20-
<si:annotation-config default-publisher-channel="defaultChannel"/>
18+
<si:annotation-config>
19+
<si:enable-publisher default-publisher-channel="defaultChannel"/>
20+
</si:annotation-config>
2121

2222
</beans>

spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515
<message-history tracked-components="publishedChannel,input,annotationTestService*"/>
1616

17-
<annotation-config default-publisher-channel="publishedChannel"/>
17+
<annotation-config>
18+
<enable-publisher default-publisher-channel="publishedChannel"/>
19+
</annotation-config>
1820

1921
<channel-interceptor pattern="none">
2022
<wire-tap channel="bar" />

src/reference/asciidoc/message-publishing.adoc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Spring Integration provides two approaches: XML and Annotation-driven.
1515
==== Annotation-driven approach via @Publisher annotation
1616

1717
The annotation-driven approach allows you to annotate any method with the `@Publisher` annotation, specifying a 'channel' attribute.
18+
Starting with _version 5.1_, to switch this functionality on, the `@EnablePublisher` annotation must be provided on some `@Configuration` class.
19+
See <<configuration-enable-integration>> for more information.
1820
The Message will be constructed from the return value of the method invocation and sent to a channel specified by the 'channel' attribute.
1921
To further manage message structure, you can also use a combination of both `@Payload` and `@Header` annotations.
2022

@@ -105,10 +107,24 @@ As with most other annotation-driven features in Spring, you will need to regist
105107
You can instead use namespace support for a more concise configuration:
106108
[source,xml]
107109
----
108-
<int:annotation-config default-publisher-channel="defaultChannel"/>
110+
<int:annotation-config>
111+
<int:enable-publisher default-publisher-channel="defaultChannel"/>
112+
</int:annotation-config>
109113
----
110114

111-
Similar to other Spring annotations (@Component, @Scheduled, etc.), `@Publisher` can also be used as a meta-annotation.
115+
For Java & Annotation Spring configuration, the `@EnablePublisher` annotation must be used:
116+
117+
[source,java]
118+
----
119+
@Configuration
120+
@EnableIntegration
121+
@EnablePublisher("defaultChannel")
122+
public class IntegrationConfiguration {
123+
...
124+
}
125+
----
126+
127+
Similar to other Spring annotations (`@Component`, `@Scheduled`, etc.), `@Publisher` can also be used as a meta-annotation.
112128
That means you can define your own annotations that will be treated in the same way as the `@Publisher` itself.
113129

114130
[source,java]

src/reference/asciidoc/whats-new.adoc

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,29 @@ Starting with _version 5.0.5_, generated bean names for the components in an `In
5151

5252
See <<java-dsl-flows>> for more information.
5353

54-
==== AMQP Changes
54+
==== Aggregator Changes
55+
56+
An aggregator now expires the group immediately, if the `groupTimeout` is evaluated to a negative value.
57+
Only `null` is considered as a signal do nothing for the current message.
58+
59+
See <<aggregator>> for more information.
60+
61+
==== @Publisher annotation changes
62+
63+
Starting with _version 5.1, the `@Publisher` AOP functionality has to be turned on explicitly via `@EnablePublisher` or via `<int:enable-publisher>` sub-element on the `<int:annotation-config>`.
64+
65+
See <<publisher-annotation>> for more information.
66+
67+
=== AMQP Changes
5568

5669
`ID` and `Timestamp` header mapping changes in the `DefaultAmqpHeaderMapper`.
5770
See the note near the bottom of <<amqp-message-headers>> for more information.
5871

5972
The `contentType` header is no longer incorrectly mapped as an entry in the general headers map.
6073
See <<amqp-content-type>> for more information.
6174

62-
==== JDBC Changes
75+
=== JDBC Changes
6376

6477
A confusing `max-rows-per-poll` property on the JDBC Inbound Channel Adapter and JDBC Outbound Gateway has been deprecated in favor newly introduced `max-rows` property.
6578

6679
See <<jdbc>> for more information.
67-
68-
==== Aggregator Changes
69-
70-
An aggregator now expires the group immediately, if the `groupTimeout` is evaluated to a negative value.
71-
Only `null` is considered as a signal do nothing for the current message.
72-
73-
See <<aggregator>> for more information.

0 commit comments

Comments
 (0)