Skip to content

Commit c4d6cf2

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 2df71fb commit c4d6cf2

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/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/main/java/org/springframework/integration/dsl/context/IntegrationFlowBeanPostProcessor.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,7 @@ else if (useFlowIdAsPrefix) {
163163
id = flowNamePrefix + id;
164164
}
165165

166-
Collection<?> messageHandlers =
167-
this.beanFactory.getBeansOfType(messageHandler.getClass(), false, false)
168-
.values();
169-
170-
if (!messageHandlers.contains(messageHandler)) {
166+
if (noBeanPresentForComponent(messageHandler)) {
171167
String handlerBeanName = generateBeanName(messageHandler, flowNamePrefix);
172168

173169
registerComponent(messageHandler, handlerBeanName, flowBeanName);
@@ -178,8 +174,7 @@ else if (useFlowIdAsPrefix) {
178174
targetIntegrationComponents.put(endpoint, id);
179175
}
180176
else {
181-
Collection<?> values = this.beanFactory.getBeansOfType(component.getClass(), false, false).values();
182-
if (!values.contains(component)) {
177+
if (noBeanPresentForComponent(component)) {
183178
if (component instanceof AbstractMessageChannel) {
184179
String channelBeanName = ((AbstractMessageChannel) component).getComponentName();
185180
if (channelBeanName == null) {
@@ -216,10 +211,7 @@ else if (component instanceof SourcePollingChannelAdapterSpec) {
216211
if (!CollectionUtils.isEmpty(componentsToRegister)) {
217212
componentsToRegister.entrySet()
218213
.stream()
219-
.filter(o ->
220-
!this.beanFactory.getBeansOfType(o.getKey().getClass(), false, false)
221-
.values()
222-
.contains(o.getKey()))
214+
.filter(o -> noBeanPresentForComponent(o.getKey()))
223215
.forEach(o ->
224216
registerComponent(o.getKey(),
225217
generateBeanName(o.getKey(), flowNamePrefix, o.getValue(),
@@ -239,9 +231,7 @@ else if (useFlowIdAsPrefix) {
239231
targetIntegrationComponents.put(pollingChannelAdapterFactoryBean, id);
240232

241233
MessageSource<?> messageSource = spec.get().getT2();
242-
if (!this.beanFactory.getBeansOfType(messageSource.getClass(), false, false)
243-
.values()
244-
.contains(messageSource)) {
234+
if (noBeanPresentForComponent(messageSource)) {
245235
String messageSourceId = id + ".source";
246236
if (messageSource instanceof NamedComponent
247237
&& ((NamedComponent) messageSource).getComponentName() != null) {
@@ -347,10 +337,7 @@ private void processIntegrationComponentSpec(String beanName, IntegrationCompone
347337

348338
componentsToRegister.entrySet()
349339
.stream()
350-
.filter(component ->
351-
!this.beanFactory.getBeansOfType(component.getKey().getClass(), false, false)
352-
.values()
353-
.contains(component.getKey()))
340+
.filter(component -> noBeanPresentForComponent(component.getKey()))
354341
.forEach(component ->
355342
registerComponent(component.getKey(),
356343
generateBeanName(component.getKey(), component.getValue())));
@@ -391,6 +378,19 @@ private void invokeBeanInitializationHooks(final String beanName, final Object b
391378
}
392379
}
393380

381+
private boolean noBeanPresentForComponent(Object instance) {
382+
if (instance instanceof NamedComponent) {
383+
String beanName = ((NamedComponent) instance).getComponentName();
384+
if (beanName != null) {
385+
return !this.beanFactory.containsBean(beanName);
386+
}
387+
}
388+
389+
Collection<?> beans = this.beanFactory.getBeansOfType(instance.getClass(), false, false).values();
390+
391+
return !beans.contains(instance);
392+
}
393+
394394
private void registerComponent(Object component, String beanName) {
395395
registerComponent(component, beanName, null);
396396
}

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;
@@ -65,6 +68,7 @@
6568
import org.springframework.integration.dsl.MessageChannels;
6669
import org.springframework.integration.dsl.Pollers;
6770
import org.springframework.integration.dsl.Transformers;
71+
import org.springframework.integration.endpoint.EventDrivenConsumer;
6872
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
6973
import org.springframework.integration.handler.GenericHandler;
7074
import org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer;
@@ -499,6 +503,18 @@ public void testNullChannelInTheEndOfFlow() {
499503
this.nullChannel.setCountsEnabled(false);
500504
}
501505

506+
@Autowired
507+
private EventDrivenConsumer flow1WithPrototypeHandlerConsumer;
508+
509+
@Autowired
510+
private EventDrivenConsumer flow2WithPrototypeHandlerConsumer;
511+
512+
@Test
513+
public void testPrototypeIsNotOverridden() {
514+
assertNotSame(this.flow1WithPrototypeHandlerConsumer.getHandler(),
515+
this.flow2WithPrototypeHandlerConsumer.getHandler());
516+
}
517+
502518
@MessagingGateway
503519
public interface ControlBusGateway {
504520

@@ -865,6 +881,31 @@ public IntegrationFlow flowWithNullChannel() {
865881
.nullChannel();
866882
}
867883

884+
@Bean
885+
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
886+
public AbstractReplyProducingMessageHandler myHandler() {
887+
return new AbstractReplyProducingMessageHandler() {
888+
889+
@Override
890+
protected Object handleRequestMessage(Message<?> requestMessage) {
891+
return requestMessage;
892+
}
893+
894+
};
895+
}
896+
897+
@Bean
898+
public IntegrationFlow flow1WithPrototypeHandler(
899+
@Qualifier("myHandler") AbstractReplyProducingMessageHandler handler) {
900+
return f -> f.handle(handler, e -> e.id("flow1WithPrototypeHandlerConsumer"));
901+
}
902+
903+
@Bean
904+
public IntegrationFlow flow2WithPrototypeHandler(
905+
@Qualifier("myHandler") AbstractReplyProducingMessageHandler handler) {
906+
return f -> f.handle(handler, e -> e.id("flow2WithPrototypeHandlerConsumer"));
907+
}
908+
868909
}
869910

870911
@Service

0 commit comments

Comments
 (0)