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
This commit is contained in:
abilan
2022-11-11 09:34:08 -05:00
parent b80f107d9b
commit bca9d27a65
2 changed files with 37 additions and 5 deletions

View File

@@ -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<? extends Class<?>> gatewayProxyInterfaces =
List<RegisteredBean> 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<Class<?>> 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) ->

View File

@@ -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;
}
}