Support @Autowired for Configurations with DSL

This commit is contained in:
Artem Bilan
2014-02-19 11:24:51 +02:00
parent c161210c3e
commit abab1af3d5
2 changed files with 82 additions and 39 deletions

View File

@@ -16,11 +16,17 @@
package org.springframework.integration.dsl.core;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -49,21 +55,35 @@ public class DslIntegrationConfigurationInitializer implements IntegrationConfig
"To use Spring Integration Java DSL the 'beanFactory' has to be an instance of 'BeanDefinitionRegistry'." +
"Consider using 'GenericApplicationContext' implementation."
);
this.checkSpecBeans(configurableListableBeanFactory);
this.initializeIntegrationFlows(configurableListableBeanFactory);
this.populateBeansFromSpecs(configurableListableBeanFactory);
}
private void checkSpecBeans(ConfigurableListableBeanFactory beanFactory) {
List<String> specBeanNames = Arrays.asList(beanFactory.getBeanNamesForType(IntegrationComponentSpec.class, false, false));
if (!specBeanNames.isEmpty()) {
throw new BeanCreationException("'IntegrationComponentSpec' beans: '" + specBeanNames + "' must be populated " +
"to target objects via 'get()' method call. It is important for @Autowired injections.");
}
}
private void initializeIntegrationFlows(ConfigurableListableBeanFactory beanFactory) {
Map<String, IntegrationFlow> integrationFlows = beanFactory.getBeansOfType(IntegrationFlow.class, false, false);
AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor = beanFactory.getBean(AutowiredAnnotationBeanPostProcessor.class);
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (Map.Entry<String, IntegrationFlow> integrationFlowEntry : integrationFlows.entrySet()) {
String flowName = integrationFlowEntry.getKey();
String[] integrationFlowBeanNames = beanFactory.getBeanNamesForType(IntegrationFlow.class, false, false);
Set<String> processedConfigurations = new HashSet<String>();
for (String flowName : integrationFlowBeanNames) {
BeanDefinition flowBeanDefinition = beanFactory.getBeanDefinition(flowName);
String configurationBeanName = flowBeanDefinition.getFactoryBeanName();
if (processedConfigurations.add(configurationBeanName)) {
autowiredAnnotationBeanPostProcessor.processInjection(beanFactory.getBean(configurationBeanName));
}
String flowNamePrefix = flowName + ":";
IntegrationFlow flow = integrationFlowEntry.getValue();
IntegrationFlow flow = beanFactory.getBean(flowName, IntegrationFlow.class);
int channelNameIndex = 0;
for (AbstractBeanDefinition beanDefinition : flow.getIntegrationComponents()) {
if (beanDefinition instanceof InstanceBeanDefinition) {
final Object instance = beanDefinition.getSource();
for (AbstractBeanDefinition component : flow.getIntegrationComponents()) {
if (component instanceof InstanceBeanDefinition) {
final Object instance = component.getSource();
Collection<?> values = beanFactory.getBeansOfType(instance.getClass(), false, false).values();
if (!values.contains(instance)) {
if (instance instanceof AbstractMessageChannel) {
@@ -71,7 +91,7 @@ public class DslIntegrationConfigurationInitializer implements IntegrationConfig
if (channelBeanName == null) {
channelBeanName = flowNamePrefix + "channel" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + channelNameIndex++;
}
registry.registerBeanDefinition(channelBeanName, beanDefinition);
registry.registerBeanDefinition(channelBeanName, component);
}
else if (instance instanceof ConsumerEndpointSpec) {
ConsumerEndpointSpec<?, ?> endpointSpec = (ConsumerEndpointSpec<?, ?>) instance;
@@ -97,30 +117,20 @@ public class DslIntegrationConfigurationInitializer implements IntegrationConfig
}
else {
String beanName = generateInstanceBeanDefinitionName(registry, instance);
registry.registerBeanDefinition(beanName, beanDefinition);
registry.registerBeanDefinition(beanName, component);
}
}
}
else {
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
BeanDefinitionReaderUtils.registerWithGeneratedName(component, registry);
}
}
registry.removeBeanDefinition(flowName);
beanFactory.destroyBean(flowName);
// registry.removeBeanDefinition(flowName);
// beanFactory.destroyBean(flowName);
}
}
private void populateBeansFromSpecs(ConfigurableListableBeanFactory beanFactory) {
Map<String, ?> specs = beanFactory.getBeansOfType(IntegrationComponentSpec.class, false, false);
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (Map.Entry<String, ?> specEntry : specs.entrySet()) {
String id = specEntry.getKey();
IntegrationComponentSpec<?, ?> spec = (IntegrationComponentSpec<?, ?>) specEntry.getValue();
registry.registerBeanDefinition(id, new InstanceBeanDefinition(spec.get()));
}
}
@SuppressWarnings("serial")
private static String generateInstanceBeanDefinitionName(BeanDefinitionRegistry registry, final Object instance) {
return BeanDefinitionReaderUtils.generateBeanName(new GenericBeanDefinition() {

View File

@@ -53,8 +53,6 @@ import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.channel.DirectChannelSpec;
import org.springframework.integration.dsl.channel.MessageChannels;
import org.springframework.integration.dsl.channel.QueueChannelSpec;
import org.springframework.integration.dsl.support.PollerSpec;
import org.springframework.integration.dsl.support.Pollers;
import org.springframework.integration.endpoint.MethodInvokingMessageSource;
import org.springframework.integration.event.core.MessagingEvent;
@@ -69,6 +67,7 @@ import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.transformer.PayloadDeserializingTransformer;
import org.springframework.integration.transformer.PayloadSerializingTransformer;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessageHeaders;
@@ -209,6 +208,7 @@ public class IntegrationFlowTests {
public void testWrongLastComponent() {
try {
new AnnotationConfigApplicationContext(InvalidLastComponentFlowContext.class);
fail("BeanCreationException expected");
}
catch (Exception e) {
assertThat(e, Matchers.instanceOf(BeanCreationException.class));
@@ -245,6 +245,19 @@ public class IntegrationFlowTests {
assertEquals("Hello, world", receive.getPayload());
}
@Test
public void testWrongConfigurationWithSpecBean() {
try {
new AnnotationConfigApplicationContext(InvalidConfigurationWithSpec.class);
fail("BeanCreationException expected");
}
catch (Exception e) {
assertThat(e, Matchers.instanceOf(IllegalArgumentException.class));
assertThat(e.getCause(), Matchers.instanceOf(BeanCreationException.class));
assertThat(e.getCause().getMessage(), Matchers.containsString("must be populated to target objects via 'get()' method call"));
}
}
@Configuration
@EnableIntegration
@@ -267,8 +280,13 @@ public class IntegrationFlowTests {
}
@Bean(name = PollerMetadata.DEFAULT_POLLER_METADATA_BEAN_NAME)
public PollerSpec poller() {
return Pollers.fixedRate(500);
public PollerMetadata poller() {
return Pollers.fixedRate(500).get();
}
@Bean
public DirectChannel inputChannel() {
return MessageChannels.direct().get();
}
}
@@ -277,27 +295,26 @@ public class IntegrationFlowTests {
@ComponentScan
public static class ContextConfiguration2 {
@Bean
public QueueChannelSpec successChannel() {
return MessageChannels.queue();
}
@Autowired
@Qualifier("inputChannel")
private MessageChannel inputChannel;
@Autowired
@Qualifier("successChannel")
private PollableChannel successChannel;
@Bean
public DirectChannelSpec inputChannel() {
return MessageChannels.direct();
}
@Bean
public Advice expressionAdvice() {
ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
advice.setOnSuccessExpression("payload");
advice.setSuccessChannel(this.successChannel().get());
advice.setSuccessChannel(this.successChannel);
return advice;
}
@Bean
public IntegrationFlow flow2() {
return IntegrationFlows.from(this.inputChannel())
return IntegrationFlows.from(this.inputChannel)
.filter(p -> p instanceof String, c -> c.id("filter"))
.<String, Integer>transform(Integer::parseInt)
.transform(new PayloadSerializingTransformer(),
@@ -323,6 +340,11 @@ public class IntegrationFlowTests {
@Configuration
public static class ContextConfiguration3 {
@Bean
public QueueChannel successChannel() {
return MessageChannels.queue().get();
}
@Bean
public AtomicReference<Object> eventHolder() {
return new AtomicReference<>();
@@ -377,7 +399,8 @@ public class IntegrationFlowTests {
.handle(this.fileWritingMessageHandler(), c -> {
FileWritingMessageHandler handler = c.get().getT2();
handler.setFileNameGenerator(message -> null);
handler.setExpectReply(false); })
handler.setExpectReply(false);
})
.get();
}
@@ -410,4 +433,14 @@ public class IntegrationFlowTests {
}
@EnableIntegration
public static class InvalidConfigurationWithSpec {
@Bean
public DirectChannelSpec invalidBean() {
return MessageChannels.direct();
}
}
}