From 2653ce9aed1f19c52fed349cefc5a7315cbe29e2 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 16 Apr 2015 10:04:34 +0100 Subject: [PATCH] INT-3701: Assist Boot with GPFB Type Determination JIRA: https://jira.spring.io/browse/INT-3701 Allow Spring Boot to determine type created by GatewayProxyFactoryBean Spring Boot's @ConditionalOnBean can be used to activate some configuration when a bean of a particular type is present in the application context. To avoid early initialization, the search for beans is performed without instantiating them, i.e. it relies on the information that's available from the bean's class and its bean definition. This causes a problem with GatewayProxyFactoryBean as its a FactoryBean so Boot's best guess is that the bean that's produced by the factory will be an Object. For cases where the bean's type signiture does not contain enougn information to determine its type, Boot looks at an attribute, factoryBeanObjectType, on the factory bean's definition. The value of this attribute can be a Class or a String class name. This commit updates MessagingGatewayRegistrar to set the value of factoryBeanObjectType attribute to be the configured service interface for the gateway. --- .../config/IntegrationConfigUtils.java | 3 +++ .../config/MessagingGatewayRegistrar.java | 16 ++++++++------- .../config/xml/GatewayParserTests-context.xml | 2 +- .../config/xml/GatewayParserTests.java | 20 +++++++++++++++++++ 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationConfigUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationConfigUtils.java index a4aebfb098..9a1161044e 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationConfigUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationConfigUtils.java @@ -34,6 +34,9 @@ public final class IntegrationConfigUtils { public static final String HANDLER_ALIAS_SUFFIX = ".handler"; + // TODO: Boot constant - move to Spring Framework? + public static final String FACTORY_BEAN_OBJECT_TYPE = "factoryBeanObjectType"; + public static void registerSpelFunctionBean(BeanDefinitionRegistry registry, String functionId, String className, String methodSignature) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SpelFunctionFactoryBean.class) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java index 0162c9a69e..d31c86953d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 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. @@ -23,12 +23,11 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - +import org.springframework.beans.BeanMetadataAttribute; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -53,12 +52,11 @@ import org.springframework.util.StringUtils; * * @author Artem Bilan * @author Gary Russell + * @author Andy Wilksinson * @since 4.0 */ public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar { - private static final Log logger = LogFactory.getLog(MessagingGatewayRegistrar.class); - @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (importingClassMetadata != null && importingClassMetadata.isAnnotated(MessagingGateway.class.getName())) { @@ -163,7 +161,11 @@ public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar gatewayProxyBuilder.addConstructorArgValue(serviceInterface); - return new BeanDefinitionHolder(gatewayProxyBuilder.getBeanDefinition(), id); + AbstractBeanDefinition beanDefinition = gatewayProxyBuilder.getBeanDefinition(); + beanDefinition.addMetadataAttribute(new BeanMetadataAttribute(IntegrationConfigUtils.FACTORY_BEAN_OBJECT_TYPE, + serviceInterface)); + + return new BeanDefinitionHolder(beanDefinition, id); } /** diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests-context.xml index b31f5a41a7..7c012803fa 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests-context.xml @@ -49,7 +49,7 @@ reactor-environment="reactorEnvironment"/> - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests.java index 0b47149b21..8b6b70b4f9 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/GatewayParserTests.java @@ -30,8 +30,12 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.integration.config.IntegrationConfigUtils; +import org.springframework.integration.gateway.RequestReplyExchanger; import org.springframework.integration.gateway.TestService; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.TestUtils; @@ -105,6 +109,22 @@ public class GatewayParserTests { assertNull(TestUtils.getPropertyValue(service, "asyncExecutor")); } + @Test + public void testFactoryBeanObjectTypeWithServiceInterface() throws Exception { + ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext)context).getBeanFactory(); + Object attribute = beanFactory.getMergedBeanDefinition("&oneWay").getAttribute( + IntegrationConfigUtils.FACTORY_BEAN_OBJECT_TYPE); + assertEquals(TestService.class.getName(), attribute); + } + + @Test + public void testFactoryBeanObjectTypeWithNoServiceInterface() throws Exception { + ConfigurableListableBeanFactory beanFactory = ((GenericApplicationContext)context).getBeanFactory(); + Object attribute = beanFactory.getMergedBeanDefinition("&defaultConfig").getAttribute( + IntegrationConfigUtils.FACTORY_BEAN_OBJECT_TYPE); + assertEquals(RequestReplyExchanger.class.getName(), attribute); + } + @Test public void testPromiseGateway() throws Exception { PollableChannel requestChannel = context.getBean("requestChannel", PollableChannel.class);