Skip to content

Commit 3a7a141

Browse files
artembilangaryrussell
authored andcommitted
INT-4539: Fix Java DSL for prototype beans
JIRA: https://jira.spring.io/browse/INT-4539 The `IntegrationFlowBeanPostProcessor` doesn't check for prototype beans and just override them in the application context with the singletons * Since we can't in the DSL understand if provided object is a prototype or not, we try to check for its bean definition by possible bean name. Use `NamedComponent` for possible bean name to check. * Remove `final` from the `IntegrationComponentSpec.get()` since its result is not visible for CGI proxies when it is declared as a `@Bean` and subsequent `getObject()` produces a new internal object * Verify prototype beans with new test in the `IntegrationFlowTests` **Cherry-pick to 5.0.x**
1 parent 11fcda4 commit 3a7a141

File tree

3 files changed

+61
-25
lines changed

3 files changed

+61
-25
lines changed

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

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,7 @@ else if (useFlowIdAsPrefix) {
160160
id = flowNamePrefix + id;
161161
}
162162

163-
Collection<?> messageHandlers =
164-
this.beanFactory.getBeansOfType(messageHandler.getClass(), false, false)
165-
.values();
166-
167-
if (!messageHandlers.contains(messageHandler)) {
163+
if (noBeanPresentForComponent(messageHandler)) {
168164
String handlerBeanName = generateBeanName(messageHandler, flowNamePrefix);
169165

170166
registerComponent(messageHandler, handlerBeanName, flowBeanName);
@@ -175,8 +171,7 @@ else if (useFlowIdAsPrefix) {
175171
targetIntegrationComponents.put(endpoint, id);
176172
}
177173
else {
178-
Collection<?> values = this.beanFactory.getBeansOfType(component.getClass(), false, false).values();
179-
if (!values.contains(component)) {
174+
if (noBeanPresentForComponent(component)) {
180175
if (component instanceof AbstractMessageChannel) {
181176
String channelBeanName = ((AbstractMessageChannel) component).getComponentName();
182177
if (channelBeanName == null) {
@@ -213,10 +208,7 @@ else if (component instanceof SourcePollingChannelAdapterSpec) {
213208
if (!CollectionUtils.isEmpty(componentsToRegister)) {
214209
componentsToRegister.entrySet()
215210
.stream()
216-
.filter(o ->
217-
!this.beanFactory.getBeansOfType(o.getKey().getClass(), false, false)
218-
.values()
219-
.contains(o.getKey()))
211+
.filter(o -> noBeanPresentForComponent(o.getKey()))
220212
.forEach(o ->
221213
registerComponent(o.getKey(),
222214
generateBeanName(o.getKey(), flowNamePrefix, o.getValue(),
@@ -236,9 +228,7 @@ else if (useFlowIdAsPrefix) {
236228
targetIntegrationComponents.put(pollingChannelAdapterFactoryBean, id);
237229

238230
MessageSource<?> messageSource = spec.get().getT2();
239-
if (!this.beanFactory.getBeansOfType(messageSource.getClass(), false, false)
240-
.values()
241-
.contains(messageSource)) {
231+
if (noBeanPresentForComponent(messageSource)) {
242232
String messageSourceId = id + ".source";
243233
if (messageSource instanceof NamedComponent
244234
&& ((NamedComponent) messageSource).getComponentName() != null) {
@@ -311,10 +301,7 @@ private void processIntegrationComponentSpec(String beanName, IntegrationCompone
311301

312302
componentsToRegister.entrySet()
313303
.stream()
314-
.filter(component ->
315-
!this.beanFactory.getBeansOfType(component.getKey().getClass(), false, false)
316-
.values()
317-
.contains(component.getKey()))
304+
.filter(component -> noBeanPresentForComponent(component.getKey()))
318305
.forEach(component ->
319306
registerComponent(component.getKey(),
320307
generateBeanName(component.getKey(), component.getValue())));
@@ -355,6 +342,19 @@ private void invokeBeanInitializationHooks(final String beanName, final Object b
355342
}
356343
}
357344

345+
private boolean noBeanPresentForComponent(Object instance) {
346+
if (instance instanceof NamedComponent) {
347+
String beanName = ((NamedComponent) instance).getComponentName();
348+
if (beanName != null) {
349+
return !this.beanFactory.containsBean(beanName);
350+
}
351+
}
352+
353+
Collection<?> beans = this.beanFactory.getBeansOfType(instance.getClass(), false, false).values();
354+
355+
return !beans.contains(instance);
356+
}
357+
358358
private void registerComponent(Object component, String beanName) {
359359
registerComponent(component, beanName, null);
360360
}

spring-integration-core/src/main/java/org/springframework/integration/dsl/IntegrationComponentSpec.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ public final String getId() {
6363
/**
6464
* @return the configured component.
6565
*/
66-
public final T get() {
66+
public T get() {
6767
if (this.target == null) {
6868
this.target = doGet();
6969
}
7070
return this.target;
7171
}
7272

7373
@Override
74-
public T getObject() throws Exception {
74+
public T getObject() {
7575
return get();
7676
}
7777

@@ -80,11 +80,6 @@ public Class<?> getObjectType() {
8080
return get().getClass();
8181
}
8282

83-
@Override
84-
public boolean isSingleton() {
85-
return true;
86-
}
87-
8883
@Override
8984
public void afterPropertiesSet() throws Exception {
9085
if (this.target instanceof InitializingBean) {

spring-integration-core/src/test/java/org/springframework/integration/dsl/flows/IntegrationFlowTests.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.hamcrest.Matchers.instanceOf;
2121
import static org.junit.Assert.assertEquals;
2222
import static org.junit.Assert.assertNotNull;
23+
import static org.junit.Assert.assertNotSame;
2324
import static org.junit.Assert.assertNull;
2425
import static org.junit.Assert.assertSame;
2526
import static org.junit.Assert.assertThat;
@@ -44,11 +45,13 @@
4445
import org.springframework.beans.factory.ListableBeanFactory;
4546
import org.springframework.beans.factory.annotation.Autowired;
4647
import org.springframework.beans.factory.annotation.Qualifier;
48+
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
4749
import org.springframework.context.ConfigurableApplicationContext;
4850
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
4951
import org.springframework.context.annotation.Bean;
5052
import org.springframework.context.annotation.ComponentScan;
5153
import org.springframework.context.annotation.Configuration;
54+
import org.springframework.context.annotation.Scope;
5255
import org.springframework.integration.MessageDispatchingException;
5356
import org.springframework.integration.MessageRejectedException;
5457
import org.springframework.integration.annotation.MessageEndpoint;
@@ -64,6 +67,7 @@
6467
import org.springframework.integration.dsl.Pollers;
6568
import org.springframework.integration.dsl.Transformers;
6669
import org.springframework.integration.dsl.channel.MessageChannels;
70+
import org.springframework.integration.endpoint.EventDrivenConsumer;
6771
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
6872
import org.springframework.integration.handler.GenericHandler;
6973
import org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer;
@@ -475,6 +479,18 @@ public void testDedicatedPollingThreadFlow() throws InterruptedException {
475479
assertEquals("dedicatedTaskScheduler-1", threadNameReference.get());
476480
}
477481

482+
@Autowired
483+
private EventDrivenConsumer flow1WithPrototypeHandlerConsumer;
484+
485+
@Autowired
486+
private EventDrivenConsumer flow2WithPrototypeHandlerConsumer;
487+
488+
@Test
489+
public void testPrototypeIsNotOverridden() {
490+
assertNotSame(this.flow1WithPrototypeHandlerConsumer.getHandler(),
491+
this.flow2WithPrototypeHandlerConsumer.getHandler());
492+
}
493+
478494
@MessagingGateway
479495
public interface ControlBusGateway {
480496

@@ -841,6 +857,31 @@ public TaskScheduler dedicatedTaskScheduler() {
841857
return new ThreadPoolTaskScheduler();
842858
}
843859

860+
@Bean
861+
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
862+
public AbstractReplyProducingMessageHandler myHandler() {
863+
return new AbstractReplyProducingMessageHandler() {
864+
865+
@Override
866+
protected Object handleRequestMessage(Message<?> requestMessage) {
867+
return requestMessage;
868+
}
869+
870+
};
871+
}
872+
873+
@Bean
874+
public IntegrationFlow flow1WithPrototypeHandler(
875+
@Qualifier("myHandler") AbstractReplyProducingMessageHandler handler) {
876+
return f -> f.handle(handler, e -> e.id("flow1WithPrototypeHandlerConsumer"));
877+
}
878+
879+
@Bean
880+
public IntegrationFlow flow2WithPrototypeHandler(
881+
@Qualifier("myHandler") AbstractReplyProducingMessageHandler handler) {
882+
return f -> f.handle(handler, e -> e.id("flow2WithPrototypeHandlerConsumer"));
883+
}
884+
844885
}
845886

846887
@Service

0 commit comments

Comments
 (0)