From e6c6db17d4873a30d21facd76f7c8ae08e01792f Mon Sep 17 00:00:00 2001 From: abilan Date: Tue, 15 Nov 2022 13:25:27 -0500 Subject: [PATCH 1/4] GH-3945: Fix `not eligible for getting processed` Fixes https://github.com/spring-projects/spring-integration/issues/3945 The `IntegrationManagementConfiguration` produces an `IntegrationManagementConfigurer` which is a `BeanPostProcessor`. According to Spring recommendation this kind of infrastructure beans must be declared as `static`. Due to an `implements ImportAware, EnvironmentAware` nature of the `IntegrationManagementConfiguration`, we cannot use `static @Bean` method. But since the `IntegrationManagementConfiguration` is not involved in any bean post-processing, it is safe to follow recommendation and mark it as a `@Role(BeanDefinition.ROLE_INFRASTRUCTURE)`. * Fix `MessagePublishingInterceptor` to initialize `MessagingTemplate` and `DestinationResolver` lazily * Fix `AbstractMethodAnnotationPostProcessor` to initialize `DestinationResolver` lazily **Cherry-pick to `5.5.x`** --- .../aop/MessagePublishingInterceptor.java | 33 ++++++++++--------- ...AbstractMethodAnnotationPostProcessor.java | 13 +++++--- .../IntegrationManagementConfiguration.java | 2 ++ 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java index 72a5dd20bca..6995967eb96 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; @@ -64,6 +65,8 @@ public class MessagePublishingInterceptor implements MethodInterceptor, BeanFact private final PublisherMetadataSource metadataSource; + private final AtomicBoolean templateInitialized = new AtomicBoolean(); + private DestinationResolver channelResolver; private BeanFactory beanFactory; @@ -94,10 +97,6 @@ public void setChannelResolver(DestinationResolver channelResolv @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; - this.messagingTemplate.setBeanFactory(beanFactory); - if (this.channelResolver == null) { - this.channelResolver = ChannelResolverUtils.getChannelResolver(this.beanFactory); - } } protected MessageBuilderFactory getMessageBuilderFactory() { @@ -111,8 +110,9 @@ protected MessageBuilderFactory getMessageBuilderFactory() { } @Override - public final Object invoke(final MethodInvocation invocation) throws Throwable { - final StandardEvaluationContext context = ExpressionUtils.createStandardEvaluationContext(this.beanFactory); + public final Object invoke(MethodInvocation invocation) throws Throwable { + initMessagingTemplateIfAny(); + StandardEvaluationContext context = ExpressionUtils.createStandardEvaluationContext(this.beanFactory); Class targetClass = AopUtils.getTargetClass(invocation.getThis()); final Method method = AopUtils.getMostSpecificMethod(invocation.getMethod(), targetClass); String[] argumentNames = resolveArgumentNames(method); @@ -143,6 +143,15 @@ public final Object invoke(final MethodInvocation invocation) throws Throwable { } } + private void initMessagingTemplateIfAny() { + if (this.templateInitialized.compareAndSet(false, true)) { + this.messagingTemplate.setBeanFactory(beanFactory); + if (this.channelResolver == null) { + this.channelResolver = ChannelResolverUtils.getChannelResolver(this.beanFactory); + } + } + } + private String[] resolveArgumentNames(Method method) { return this.parameterNameDiscoverer.getParameterNames(method); } @@ -163,20 +172,14 @@ private void publishMessage(Method method, StandardEvaluationContext context) { } Message message = builder.build(); String channelName = this.metadataSource.getChannelName(method); - MessageChannel channel = null; if (channelName != null) { - Assert.state(this.channelResolver != null, "ChannelResolver is required to resolve channel names."); - channel = this.channelResolver.resolveDestination(channelName); - } - if (channel != null) { - this.messagingTemplate.send(channel, message); + this.messagingTemplate.send(channelName, message); } else { String channelNameToUse = this.defaultChannelName; if (channelNameToUse != null && this.messagingTemplate.getDefaultDestination() == null) { Assert.state(this.channelResolver != null, "ChannelResolver is required to resolve channel names."); - this.messagingTemplate.setDefaultChannel( - this.channelResolver.resolveDestination(channelNameToUse)); + this.messagingTemplate.setDefaultChannel(this.channelResolver.resolveDestination(channelNameToUse)); this.defaultChannelName = null; } this.messagingTemplate.send(message); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java index b3903955e53..c63843c48f1 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java @@ -141,7 +141,7 @@ public abstract class AbstractMethodAnnotationPostProcessor channelResolver; + private volatile DestinationResolver channelResolver; @SuppressWarnings(UNCHECKED) public AbstractMethodAnnotationPostProcessor() { @@ -154,10 +154,10 @@ public AbstractMethodAnnotationPostProcessor() { public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; this.definitionRegistry = (BeanDefinitionRegistry) beanFactory; - this.conversionService = this.beanFactory.getConversionService() != null - ? this.beanFactory.getConversionService() - : DefaultConversionService.getSharedInstance(); - this.channelResolver = ChannelResolverUtils.getChannelResolver(beanFactory); + this.conversionService = + this.beanFactory.getConversionService() != null + ? this.beanFactory.getConversionService() + : DefaultConversionService.getSharedInstance(); } protected ConfigurableListableBeanFactory getBeanFactory() { @@ -173,6 +173,9 @@ protected ConversionService getConversionService() { } protected DestinationResolver getChannelResolver() { + if (this.channelResolver == null) { + this.channelResolver = ChannelResolverUtils.getChannelResolver(beanFactory); + } return this.channelResolver; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationManagementConfiguration.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationManagementConfiguration.java index 277f1171f7d..22018753fbf 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationManagementConfiguration.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationManagementConfiguration.java @@ -44,9 +44,11 @@ * * @author Artem Bilan * @author Gary Russell + * * @since 4.2 */ @Configuration(proxyBeanMethods = false) +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class IntegrationManagementConfiguration implements ImportAware, EnvironmentAware { private AnnotationAttributes attributes; From 6e9f3246ea491a064089641d1fa0b47fd97047ef Mon Sep 17 00:00:00 2001 From: abilan Date: Tue, 15 Nov 2022 13:59:24 -0500 Subject: [PATCH 2/4] * Use `getChannelResolver()` internally in the `AbstractMethodAnnotationPostProcessor` instead of direct property access which might not be initialized yet * Use a plain `boolean` for `templateInitialized` in the `MessagePublishingInterceptor` to avoid skips in other thread where and move on with still not initialized properties --- .../integration/aop/MessagePublishingInterceptor.java | 11 ++++++----- .../config/AbstractMethodAnnotationPostProcessor.java | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java index 6995967eb96..98425e87a2b 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java @@ -65,18 +65,18 @@ public class MessagePublishingInterceptor implements MethodInterceptor, BeanFact private final PublisherMetadataSource metadataSource; - private final AtomicBoolean templateInitialized = new AtomicBoolean(); - private DestinationResolver channelResolver; private BeanFactory beanFactory; private MessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory(); - private boolean messageBuilderFactorySet; - private String defaultChannelName; + private volatile boolean messageBuilderFactorySet; + + private volatile boolean templateInitialized; + public MessagePublishingInterceptor(PublisherMetadataSource metadataSource) { Assert.notNull(metadataSource, "metadataSource must not be null"); this.metadataSource = metadataSource; @@ -144,11 +144,12 @@ public final Object invoke(MethodInvocation invocation) throws Throwable { } private void initMessagingTemplateIfAny() { - if (this.templateInitialized.compareAndSet(false, true)) { + if (!this.templateInitialized) { this.messagingTemplate.setBeanFactory(beanFactory); if (this.channelResolver == null) { this.channelResolver = ChannelResolverUtils.getChannelResolver(this.beanFactory); } + this.templateInitialized = true; } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java index c63843c48f1..e3e78520a8c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java @@ -572,7 +572,7 @@ protected AbstractEndpoint createEndpoint(MessageHandler handler, @SuppressWarni if (StringUtils.hasText(inputChannelName)) { MessageChannel inputChannel; try { - inputChannel = this.channelResolver.resolveDestination(inputChannelName); + inputChannel = getChannelResolver().resolveDestination(inputChannelName); } catch (DestinationResolutionException e) { if (e.getCause() instanceof NoSuchBeanDefinitionException) { From faeb631fe63e6066bb5fac42acab5195caa74ee5 Mon Sep 17 00:00:00 2001 From: abilan Date: Tue, 15 Nov 2022 14:00:05 -0500 Subject: [PATCH 3/4] * Remove unused import --- .../integration/aop/MessagePublishingInterceptor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java index 98425e87a2b..347bd9e45e3 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java @@ -19,7 +19,6 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; From b45e95a80357cbe17b64e95e7e75d3bfe51fd603 Mon Sep 17 00:00:00 2001 From: abilan Date: Tue, 15 Nov 2022 14:09:32 -0500 Subject: [PATCH 4/4] * Fix `this.` prefix for `beanFactory` property reference --- .../integration/aop/MessagePublishingInterceptor.java | 2 +- .../config/AbstractMethodAnnotationPostProcessor.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java index 347bd9e45e3..1c61c845a66 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/MessagePublishingInterceptor.java @@ -144,7 +144,7 @@ public final Object invoke(MethodInvocation invocation) throws Throwable { private void initMessagingTemplateIfAny() { if (!this.templateInitialized) { - this.messagingTemplate.setBeanFactory(beanFactory); + this.messagingTemplate.setBeanFactory(this.beanFactory); if (this.channelResolver == null) { this.channelResolver = ChannelResolverUtils.getChannelResolver(this.beanFactory); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java index e3e78520a8c..4645a584315 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractMethodAnnotationPostProcessor.java @@ -174,7 +174,7 @@ protected ConversionService getConversionService() { protected DestinationResolver getChannelResolver() { if (this.channelResolver == null) { - this.channelResolver = ChannelResolverUtils.getChannelResolver(beanFactory); + this.channelResolver = ChannelResolverUtils.getChannelResolver(this.beanFactory); } return this.channelResolver; }