From bca9d27a65dafe16f83dfd6bd8ab8359059a7404 Mon Sep 17 00:00:00 2001 From: abilan Date: Fri, 11 Nov 2022 09:34:08 -0500 Subject: [PATCH] Fix Gateway proxy registration for AOT The `GatewayProxyInstantiationPostProcessor` does nothing on the AOT phase. Therefore, scanned and imported beans for `@MessagingGateway` are not decorated after AOT * Implement a `BeanRegistrationAotProcessor` in the `GatewayProxyInstantiationPostProcessor` to `RegisteredBean.getMergedBeanDefinition()` withe respective `AnnotationGatewayProxyFactoryBean` and its requirements for ctor arg and `targetType` * Scan for the `@MessagingGateway` bean in the `GatewayProxyInitializationAotProcessor` to register respective proxy hints --- ...atewayProxyInitializationAotProcessor.java | 22 +++++++++++++++---- ...atewayProxyInstantiationPostProcessor.java | 20 ++++++++++++++++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aot/GatewayProxyInitializationAotProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aot/GatewayProxyInitializationAotProcessor.java index 87958d624c..d67ca376f2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aot/GatewayProxyInitializationAotProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aot/GatewayProxyInitializationAotProcessor.java @@ -18,6 +18,7 @@ package org.springframework.integration.aot; import java.util.Arrays; import java.util.List; +import java.util.stream.Stream; import org.springframework.aop.framework.AopProxyUtils; import org.springframework.aop.framework.ProxyFactoryBean; @@ -26,12 +27,15 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContrib import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.RegisteredBean; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.integration.annotation.MessagingGateway; import org.springframework.integration.gateway.GatewayProxyFactoryBean; import org.springframework.integration.gateway.RequestReplyExchanger; + /** * A {@link BeanFactoryInitializationAotProcessor} for registering proxy interfaces - * of the {@link GatewayProxyFactoryBean} beans. + * of the {@link GatewayProxyFactoryBean} beans or {@link MessagingGateway} interfaces. * * @author Artem Bilan * @@ -41,13 +45,23 @@ class GatewayProxyInitializationAotProcessor implements BeanFactoryInitializatio @Override public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { - List> gatewayProxyInterfaces = + List registeredBeans = Arrays.stream(beanFactory.getBeanDefinitionNames()) .map((beanName) -> RegisteredBean.of(beanFactory, beanName)) - .filter((bean) -> ProxyFactoryBean.class.isAssignableFrom(bean.getBeanClass())) - .map((bean) -> bean.getBeanType().getGeneric(0).resolve(RequestReplyExchanger.class)) .toList(); + Stream> gatewayProxyInterfaces = + Stream.concat( + registeredBeans.stream() + .filter(bean -> ProxyFactoryBean.class.isAssignableFrom(bean.getBeanClass())) + .map((bean) -> + bean.getBeanType().getGeneric(0).resolve(RequestReplyExchanger.class)), + registeredBeans.stream() + .map(RegisteredBean::getBeanClass) + .filter(beanClass -> + beanClass.isInterface() && + AnnotatedElementUtils.hasAnnotation(beanClass, MessagingGateway.class))); + return (generationContext, beanFactoryInitializationCode) -> { ProxyHints proxyHints = generationContext.getRuntimeHints().proxies(); gatewayProxyInterfaces.forEach((gatewayInterface) -> diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/GatewayProxyInstantiationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/GatewayProxyInstantiationPostProcessor.java index 6d743e2bcc..9813df8f06 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/GatewayProxyInstantiationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/GatewayProxyInstantiationPostProcessor.java @@ -18,12 +18,17 @@ package org.springframework.integration.config; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; +import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; +import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RegisteredBean; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.integration.annotation.MessagingGateway; import org.springframework.integration.gateway.AnnotationGatewayProxyFactoryBean; @@ -39,7 +44,7 @@ import org.springframework.integration.gateway.AnnotationGatewayProxyFactoryBean * @see AnnotationGatewayProxyFactoryBean */ class GatewayProxyInstantiationPostProcessor implements - InstantiationAwareBeanPostProcessor, ApplicationContextAware { + InstantiationAwareBeanPostProcessor, BeanRegistrationAotProcessor, ApplicationContextAware { private final BeanDefinitionRegistry registry; @@ -77,4 +82,17 @@ class GatewayProxyInstantiationPostProcessor implements return null; } + @Override + public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { + Class beanClass = registeredBean.getBeanClass(); + if (beanClass.isInterface() && AnnotatedElementUtils.hasAnnotation(beanClass, MessagingGateway.class)) { + RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition(); + beanDefinition.setBeanClass(AnnotationGatewayProxyFactoryBean.class); + beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanClass); + beanDefinition.setTargetType( + ResolvableType.forClassWithGenerics(AnnotationGatewayProxyFactoryBean.class, beanClass)); + } + return null; + } + }