INT-3250: Add @EnableIntegration Infrastructure
JIRA: https://jira.springsource.org/browse/INT-3250 * The main purpose of this change to move all infrastructure bean definitions from `AbstractIntegrationNamespaceHandler` to a new `IntegrationRegistrar`. * `IntegrationRegistrar` is invoked by the standard `@Configuration` process and also directly from `AbstractIntegrationNamespaceHandler`. * Provide some refactoring for consistency. * Add AnnotationContext tests INT-3250: Polishing * Remove `@EnableIntegration#defaultPublisherChannel` * Revert `#jsonPath` & `#xpath` registration logic * Fix for DEBUG message on each parse JIRA: https://jira.springsource.org/browse/INT-3258 INT-3250 Fix JavaDocs & IDEA+Gradle srcDirs issue INT-3250: Revert `build.gradle` changes INT-3250 Polishing * Remove commented out code * Add javadoc to IntegrationRegistrar.registerBeanDefinitions() * Fix javadoc links to other Spring projects (and JVM, JEE) * Add reference documentation and what's new
This commit is contained in:
committed by
Gary Russell
parent
4ac1a9113a
commit
4ae5152eff
14
build.gradle
14
build.gradle
@@ -32,6 +32,19 @@ allprojects {
|
||||
maven { url 'http://repo.spring.io/plugins-release' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
'http://docs.oracle.com/javase/7/docs/api/',
|
||||
'http://docs.oracle.com/javaee/6/api/',
|
||||
'http://docs.spring.io/spring/docs/current/javadoc-api/',
|
||||
'http://docs.spring.io/spring-amqp/docs/latest-ga/api/',
|
||||
'http://docs.spring.io/spring-data-gemfire/docs/current/api/',
|
||||
'http://docs.spring.io/spring-data/data-mongo/docs/current/api/',
|
||||
'http://docs.spring.io/spring-data/data-redis/docs/current/api/',
|
||||
'http://docs.spring.io/spring-social-twitter/docs/current/api/',
|
||||
'http://docs.spring.io/spring-ws/sites/2.0/apidocs/'
|
||||
] as String[]
|
||||
|
||||
}
|
||||
|
||||
subprojects { subproject ->
|
||||
@@ -614,6 +627,7 @@ task api(type: Javadoc) {
|
||||
options.header = rootProject.description
|
||||
options.overview = 'src/api/overview.html'
|
||||
options.stylesheetFile = file("src/api/stylesheet.css")
|
||||
options.links(project.ext.javadocLinks)
|
||||
source subprojects.collect { project ->
|
||||
project.sourceSets.main.allJava
|
||||
}
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright 2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor;
|
||||
import org.springframework.integration.channel.DefaultHeaderChannelRegistry;
|
||||
import org.springframework.integration.config.annotation.EnableIntegration;
|
||||
import org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.context.IntegrationProperties;
|
||||
import org.springframework.integration.expression.IntegrationEvaluationContextAwareBeanPostProcessor;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ImportBeanDefinitionRegistrar} implementation that configures integration infrastructure.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.0
|
||||
*/
|
||||
public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(IntegrationRegistrar.class);
|
||||
|
||||
private static final Set<Integer> registriesProcessed = new HashSet<Integer>();
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the framework when an @EnableIntegration annotation is encountered.
|
||||
* Also called with {@code null} {@code importingClassMetadata} from {@code AbstractIntegrationNamespaceHandler}
|
||||
* to register the same beans when using XML configuration. Also called by {@code AnnotationConfigParser}
|
||||
* to register the messaging annotation post processors (for {@code <int:annotation-config/>}).
|
||||
*/
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
this.registerImplicitChannelCreator(registry);
|
||||
this.registerIntegrationEvaluationContext(registry);
|
||||
this.registerIntegrationProperties(registry);
|
||||
this.registerHeaderChannelRegistry(registry);
|
||||
this.registerBuiltInBeans(registry);
|
||||
this.registerDefaultConfiguringBeanFactoryPostProcessor(registry);
|
||||
if (importingClassMetadata != null) {
|
||||
this.registerMessagingAnnotationPostProcessors(importingClassMetadata, registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will auto-register a ChannelInitializer which could also be overridden by the user
|
||||
* by simply registering a ChannelInitializer {@code <bean>} with its {@code autoCreate} property
|
||||
* set to false to suppress channel creation.
|
||||
* It will also register a ChannelInitializer$AutoCreateCandidatesCollector which simply collects candidate channel names.
|
||||
*
|
||||
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s.
|
||||
*/
|
||||
private void registerImplicitChannelCreator(BeanDefinitionRegistry registry) {
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.CHANNEL_INITIALIZER_BEAN_NAME)) {
|
||||
String channelsAutoCreateExpression = IntegrationProperties.getExpressionFor(IntegrationProperties.CHANNELS_AUTOCREATE);
|
||||
BeanDefinitionBuilder channelDef = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IntegrationNamespaceUtils.BASE_PACKAGE + ".config.xml.ChannelInitializer")
|
||||
.addPropertyValue("autoCreate", channelsAutoCreateExpression);
|
||||
BeanDefinitionHolder channelCreatorHolder = new BeanDefinitionHolder(channelDef.getBeanDefinition(),
|
||||
IntegrationContextUtils.CHANNEL_INITIALIZER_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(channelCreatorHolder, registry);
|
||||
}
|
||||
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder channelRegistryBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IntegrationNamespaceUtils.BASE_PACKAGE + ".config.xml.ChannelInitializer$AutoCreateCandidatesCollector");
|
||||
channelRegistryBuilder.addConstructorArgValue(new ManagedSet<String>());
|
||||
BeanDefinitionHolder channelRegistryHolder = new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(),
|
||||
IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(channelRegistryHolder, registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register {@code integrationGlobalProperties} bean if necessary.
|
||||
*
|
||||
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s.
|
||||
*/
|
||||
private void registerIntegrationProperties(BeanDefinitionRegistry registry) {
|
||||
boolean alreadyRegistered = false;
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) registry)
|
||||
.containsBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(this.classLoader);
|
||||
try {
|
||||
Resource[] defaultResources = resourceResolver.getResources("classpath*:META-INF/spring.integration.default.properties");
|
||||
Resource[] userResources = resourceResolver.getResources("classpath*:META-INF/spring.integration.properties");
|
||||
|
||||
List<Resource> resources = new LinkedList<Resource>(Arrays.asList(defaultResources));
|
||||
resources.addAll(Arrays.asList(userResources));
|
||||
|
||||
BeanDefinitionBuilder integrationPropertiesBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(PropertiesFactoryBean.class)
|
||||
.addPropertyValue("locations", resources);
|
||||
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME,
|
||||
integrationPropertiesBuilder.getBeanDefinition());
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn("Cannot load 'spring.integration.properties' Resources.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register {@link IntegrationEvaluationContextFactoryBean} bean
|
||||
* and {@link IntegrationEvaluationContextAwareBeanPostProcessor}, if necessary.
|
||||
*
|
||||
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s.
|
||||
*/
|
||||
private void registerIntegrationEvaluationContext(BeanDefinitionRegistry registry) {
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder integrationEvaluationContextBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IntegrationEvaluationContextFactoryBean.class);
|
||||
integrationEvaluationContextBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
BeanDefinitionHolder integrationEvaluationContextHolder =
|
||||
new BeanDefinitionHolder(integrationEvaluationContextBuilder.getBeanDefinition(),
|
||||
IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
|
||||
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder,
|
||||
registry);
|
||||
|
||||
RootBeanDefinition integrationEvalContextBPP = new RootBeanDefinition(IntegrationEvaluationContextAwareBeanPostProcessor.class);
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(integrationEvalContextBPP, registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register {@code jsonPath} and {@code xpath} SpEL-function beans, if necessary.
|
||||
*
|
||||
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s.
|
||||
*/
|
||||
private void registerBuiltInBeans(BeanDefinitionRegistry registry) {
|
||||
int registryId = System.identityHashCode(registry);
|
||||
|
||||
String jsonPathBeanName = "jsonPath";
|
||||
boolean alreadyRegistered = false;
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) registry).containsBean(jsonPathBeanName);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = registry.isBeanNameInUse(jsonPathBeanName);
|
||||
}
|
||||
if (!alreadyRegistered && !registriesProcessed.contains(registryId)) {
|
||||
Class<?> jsonPathClass = null;
|
||||
try {
|
||||
jsonPathClass = ClassUtils.forName("com.jayway.jsonpath.JsonPath", this.classLoader);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
logger.debug("SpEL function '#jsonPath' isn't registered: there is no jayway json-path.jar on the classpath.");
|
||||
}
|
||||
|
||||
if (jsonPathClass != null) {
|
||||
IntegrationNamespaceUtils.registerSpelFunctionBean(registry, jsonPathBeanName,
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".json.JsonPathUtils", "evaluate");
|
||||
}
|
||||
}
|
||||
|
||||
alreadyRegistered = false;
|
||||
String xpathBeanName = "xpath";
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) registry).containsBean(xpathBeanName);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = registry.isBeanNameInUse(xpathBeanName);
|
||||
}
|
||||
if (!alreadyRegistered && !registriesProcessed.contains(registryId)) {
|
||||
Class<?> xpathClass = null;
|
||||
try {
|
||||
xpathClass = ClassUtils.forName(IntegrationNamespaceUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils",
|
||||
this.classLoader);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
logger.debug("SpEL function '#xpath' isn't registered: there is no spring-integration-xml.jar on the classpath.");
|
||||
}
|
||||
|
||||
if (xpathClass != null) {
|
||||
IntegrationNamespaceUtils.registerSpelFunctionBean(registry, xpathBeanName,
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils", "evaluate");
|
||||
}
|
||||
}
|
||||
|
||||
registriesProcessed.add(registryId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register {@code DefaultConfiguringBeanFactoryPostProcessor}, if necessary.
|
||||
*
|
||||
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s.
|
||||
*/
|
||||
private void registerDefaultConfiguringBeanFactoryPostProcessor(BeanDefinitionRegistry registry) {
|
||||
boolean alreadyRegistered = false;
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) registry).containsBean(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
BeanDefinitionBuilder postProcessorBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IntegrationNamespaceUtils.BASE_PACKAGE + ".config.xml.DefaultConfiguringBeanFactoryPostProcessor");
|
||||
BeanDefinitionHolder postProcessorHolder = new BeanDefinitionHolder(
|
||||
postProcessorBuilder.getBeanDefinition(), IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(postProcessorHolder, registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link DefaultHeaderChannelRegistry} in the given {@link BeanDefinitionRegistry}, if necessary.
|
||||
*
|
||||
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s.
|
||||
*/
|
||||
private void registerHeaderChannelRegistry(BeanDefinitionRegistry registry) {
|
||||
boolean alreadyRegistered = false;
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) registry).containsBean(IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("No bean named '" + IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME +
|
||||
"' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.");
|
||||
}
|
||||
BeanDefinitionBuilder schedulerBuilder = BeanDefinitionBuilder.genericBeanDefinition(DefaultHeaderChannelRegistry.class);
|
||||
BeanDefinitionHolder replyChannelRegistryComponent = new BeanDefinitionHolder(
|
||||
schedulerBuilder.getBeanDefinition(),
|
||||
IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(replyChannelRegistryComponent, registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register {@link MessagingAnnotationPostProcessor} and {@link PublisherAnnotationBeanPostProcessor}, if necessary.
|
||||
* Inject {@code defaultPublishedChannel} from provided {@link AnnotationMetadata}, if any.
|
||||
*
|
||||
* @param meta The {@link AnnotationMetadata} to get additional properties for {@link org.springframework.beans.factory.config.BeanDefinition}s.
|
||||
* @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s.
|
||||
*/
|
||||
private void registerMessagingAnnotationPostProcessors(AnnotationMetadata meta, BeanDefinitionRegistry registry) {
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME)) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MessagingAnnotationPostProcessor.class)
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME, builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME)) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PublisherAnnotationBeanPostProcessor.class)
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
Map<String, Object> attrs = meta.getAnnotationAttributes(EnableIntegration.class.getName());
|
||||
|
||||
String defaultPublisherChannel = (String) attrs.get("defaultPublisherChannel");
|
||||
if (StringUtils.hasText(defaultPublisherChannel)) {
|
||||
builder.addPropertyReference("defaultChannel", defaultPublisherChannel);
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME, builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.config.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.integration.config.IntegrationRegistrar;
|
||||
|
||||
/**
|
||||
* Add this annotation to an {@code @Configuration} class to have
|
||||
* the imported Spring Integration configuration :
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableIntegration
|
||||
* @ComponentScan(basePackageClasses = { MyConfiguration.class })
|
||||
* public class MyIntegrationConfiguration {
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @since 4.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(IntegrationRegistrar.class)
|
||||
public @interface EnableIntegration {
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.ConsumerEndpointFactoryBean;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@@ -122,9 +123,9 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
|
||||
String inputChannelName = element.getAttribute(inputChannelAttributeName);
|
||||
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(inputChannelName)) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME)) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME)) {
|
||||
BeanDefinition channelRegistry = parserContext.getRegistry().
|
||||
getBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
getBeanDefinition(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
ConstructorArgumentValues caValues = channelRegistry.getConstructorArgumentValues();
|
||||
ValueHolder vh = caValues.getArgumentValue(0, Collection.class);
|
||||
if (vh == null) { //although it should never happen if it does we can fix it
|
||||
@@ -137,7 +138,7 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
|
||||
}
|
||||
else {
|
||||
parserContext.getReaderContext().error("Failed to locate '" +
|
||||
ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME + "'", parserContext.getRegistry());
|
||||
IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME + "'", parserContext.getRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -16,40 +16,19 @@
|
||||
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandler;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.integration.channel.DefaultHeaderChannelRegistry;
|
||||
import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
|
||||
import org.springframework.integration.config.xml.ChannelInitializer.AutoCreateCandidatesCollector;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.context.IntegrationProperties;
|
||||
import org.springframework.integration.expression.IntegrationEvaluationContextAwareBeanPostProcessor;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.integration.config.IntegrationRegistrar;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -59,6 +38,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
@@ -66,238 +46,21 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
|
||||
|
||||
private static final String VERSION = "4.0";
|
||||
|
||||
public static final String CHANNEL_INITIALIZER_BEAN_NAME = "channelInitializer";
|
||||
|
||||
private static final String DEFAULT_CONFIGURING_POSTPROCESSOR_SIMPLE_CLASS_NAME =
|
||||
"DefaultConfiguringBeanFactoryPostProcessor";
|
||||
|
||||
private static final String DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME =
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".internal" + DEFAULT_CONFIGURING_POSTPROCESSOR_SIMPLE_CLASS_NAME;
|
||||
|
||||
|
||||
private final NamespaceHandlerDelegate delegate = new NamespaceHandlerDelegate();
|
||||
|
||||
|
||||
@Override
|
||||
public final BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
this.verifySchemaVersion(element, parserContext);
|
||||
this.registerImplicitChannelCreator(parserContext);
|
||||
this.registerIntegrationEvaluationContext(parserContext);
|
||||
this.registerIntegrationProperties(parserContext);
|
||||
this.registerHeaderChannelRegistry(parserContext);
|
||||
this.registerBuiltInBeans(parserContext);
|
||||
this.registerDefaultConfiguringBeanFactoryPostProcessorIfNecessary(parserContext);
|
||||
new IntegrationRegistrar().registerBeanDefinitions(null, parserContext.getRegistry());
|
||||
return this.delegate.parse(element, parserContext);
|
||||
}
|
||||
|
||||
private void registerIntegrationProperties(ParserContext parserContext) {
|
||||
|
||||
boolean alreadyRegistered = false;
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) registry)
|
||||
.containsBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
ResourcePatternResolver resourceResolver =
|
||||
new PathMatchingResourcePatternResolver(parserContext.getReaderContext().getBeanClassLoader());
|
||||
try {
|
||||
Resource[] defaultResources = resourceResolver.getResources("classpath*:META-INF/spring.integration.default.properties");
|
||||
Resource[] userResources = resourceResolver.getResources("classpath*:META-INF/spring.integration.properties");
|
||||
|
||||
List<Resource> resources = new LinkedList<Resource>(Arrays.asList(defaultResources));
|
||||
resources.addAll(Arrays.asList(userResources));
|
||||
|
||||
BeanDefinitionBuilder integrationPropertiesBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(PropertiesFactoryBean.class)
|
||||
.addPropertyValue("locations", resources);
|
||||
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME,
|
||||
integrationPropertiesBuilder.getBeanDefinition());
|
||||
}
|
||||
catch (IOException e) {
|
||||
parserContext.getReaderContext().warning("Cannot load 'spring.integration.properties' Resources.", null, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext) {
|
||||
return this.delegate.decorate(source, definition, parserContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method will auto-register a ChannelInitializer which could also be overridden by the user
|
||||
* by simply registering a ChannelInitializer <bean> with its 'autoCreate' property set to false to suppress channel creation.
|
||||
* It will also register a ChannelInitializer$AutoCreateCandidatesCollector which simply collects candidate channel names.
|
||||
*/
|
||||
private void registerImplicitChannelCreator(ParserContext parserContext) {
|
||||
// ChannelInitializer
|
||||
boolean alreadyRegistered = false;
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
// unlike DefaultConfiguringBeanFactoryPostProcessor we need one of these per registry
|
||||
// therefore we need to call containsBeanDefinition(..) which does not consider parent registry
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).containsBeanDefinition(CHANNEL_INITIALIZER_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(CHANNEL_INITIALIZER_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
String channelsAutoCreateExpression = IntegrationProperties.getExpressionFor(IntegrationProperties.CHANNELS_AUTOCREATE);
|
||||
BeanDefinitionBuilder channelDef = BeanDefinitionBuilder.genericBeanDefinition(ChannelInitializer.class)
|
||||
.addPropertyValue("autoCreate", channelsAutoCreateExpression);
|
||||
BeanDefinitionHolder channelCreatorHolder = new BeanDefinitionHolder(channelDef.getBeanDefinition(), CHANNEL_INITIALIZER_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(channelCreatorHolder, parserContext.getRegistry());
|
||||
}
|
||||
// ChannelInitializer$AutoCreateCandidatesCollector
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
// unlike DefaultConfiguringBeanFactoryPostProcessor, we need one of these per registry
|
||||
// therefore we need to call containsBeanDefinition(..) which does not consider the parent registry
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).
|
||||
containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
BeanDefinitionBuilder channelRegistryBuilder = BeanDefinitionBuilder.genericBeanDefinition(AutoCreateCandidatesCollector.class);
|
||||
channelRegistryBuilder.addConstructorArgValue(new ManagedSet<String>());
|
||||
BeanDefinitionHolder channelRegistryHolder =
|
||||
new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(), ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(channelRegistryHolder, parserContext.getRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
private void registerIntegrationEvaluationContext(ParserContext parserContext) {
|
||||
boolean alreadyRegistered = false;
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
// unlike DefaultConfiguringBeanFactoryPostProcessor, we need one of these per registry
|
||||
// therefore we need to call containsBeanDefinition(..) which does not consider the parent registry
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).containsBeanDefinition(
|
||||
IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(
|
||||
IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
BeanDefinitionBuilder integrationEvaluationContextBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(IntegrationEvaluationContextFactoryBean.class);
|
||||
integrationEvaluationContextBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
BeanDefinitionHolder integrationEvaluationContextHolder = new BeanDefinitionHolder(
|
||||
integrationEvaluationContextBuilder.getBeanDefinition(),
|
||||
IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder,
|
||||
parserContext.getRegistry());
|
||||
RootBeanDefinition integrationEvalContextBPP = new RootBeanDefinition(
|
||||
IntegrationEvaluationContextAwareBeanPostProcessor.class);
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(integrationEvalContextBPP, parserContext.getRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
private void registerBuiltInBeans(ParserContext parserContext) {
|
||||
String jsonPathBeanName = "jsonPath";
|
||||
boolean alreadyRegistered = false;
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).containsBean(jsonPathBeanName);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(jsonPathBeanName);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
Class<?> jsonPathClass = null;
|
||||
try {
|
||||
jsonPathClass = ClassUtils.forName("com.jayway.jsonpath.JsonPath", parserContext.getReaderContext().getBeanClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
logger.debug("SpEL function '#jsonPath' isn't registered: there is no jayway json-path.jar on the classpath.");
|
||||
}
|
||||
|
||||
if (jsonPathClass != null) {
|
||||
IntegrationNamespaceUtils.registerSpelFunctionBean(parserContext.getRegistry(), jsonPathBeanName,
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".json.JsonPathUtils", "evaluate");
|
||||
}
|
||||
}
|
||||
|
||||
String xpathBeanName = "xpath";
|
||||
alreadyRegistered = false;
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).containsBean(xpathBeanName);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(xpathBeanName);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
Class<?> xpathClass = null;
|
||||
try {
|
||||
xpathClass = ClassUtils.forName(IntegrationNamespaceUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils",
|
||||
parserContext.getReaderContext().getBeanClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
logger.debug("SpEL function '#xpath' isn't registered: there is no spring-integration-xml.jar on the classpath.");
|
||||
}
|
||||
|
||||
if (xpathClass != null) {
|
||||
IntegrationNamespaceUtils.registerSpelFunctionBean(parserContext.getRegistry(), xpathBeanName,
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils", "evaluate");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.doRegisterBuiltInBeans(parserContext);
|
||||
}
|
||||
|
||||
protected void doRegisterBuiltInBeans(ParserContext parserContext) {
|
||||
|
||||
}
|
||||
|
||||
private void registerDefaultConfiguringBeanFactoryPostProcessorIfNecessary(ParserContext parserContext) {
|
||||
boolean alreadyRegistered = false;
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).containsBean(DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
BeanDefinitionBuilder postProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".config.xml." + DEFAULT_CONFIGURING_POSTPROCESSOR_SIMPLE_CLASS_NAME);
|
||||
BeanDefinitionHolder postProcessorHolder = new BeanDefinitionHolder(
|
||||
postProcessorBuilder.getBeanDefinition(), DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(postProcessorHolder, parserContext.getRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a DefaultHeaderChannelRegistry in the given BeanDefinitionRegistry, if necessary.
|
||||
*/
|
||||
private void registerHeaderChannelRegistry(ParserContext parserContext) {
|
||||
boolean alreadyRegistered = false;
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry())
|
||||
.containsBean(IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(
|
||||
IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("No bean named '" + IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME +
|
||||
"' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.");
|
||||
}
|
||||
BeanDefinitionBuilder schedulerBuilder = BeanDefinitionBuilder.genericBeanDefinition(DefaultHeaderChannelRegistry.class);
|
||||
BeanDefinitionHolder replyChannelRegistryComponent = new BeanDefinitionHolder(
|
||||
schedulerBuilder.getBeanDefinition(),
|
||||
IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(replyChannelRegistryComponent, parserContext.getRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected final void registerBeanDefinitionDecorator(String elementName, BeanDefinitionDecorator decorator) {
|
||||
this.delegate.doRegisterBeanDefinitionDecorator(elementName, decorator);
|
||||
}
|
||||
@@ -346,4 +109,5 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -16,42 +16,36 @@
|
||||
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.integration.config.IntegrationRegistrar;
|
||||
|
||||
/**
|
||||
* Parser for the <annotation-config> element of the integration namespace.
|
||||
* Adds a {@link org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor}
|
||||
* and a {@link org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor}
|
||||
* to the application context.
|
||||
*
|
||||
* Just delegate the real configuration to the {@link IntegrationRegistrar}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class AnnotationConfigParser implements BeanDefinitionParser {
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
RootBeanDefinition messagingAnnotationPostProcessorDef = new RootBeanDefinition(
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".config.annotation.MessagingAnnotationPostProcessor");
|
||||
messagingAnnotationPostProcessorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
String messagingAnnotationPostProcessorName = IntegrationNamespaceUtils.BASE_PACKAGE + ".internalMessagingAnnotationPostProcessor";
|
||||
parserContext.getRegistry().registerBeanDefinition(messagingAnnotationPostProcessorName, messagingAnnotationPostProcessorDef);
|
||||
RootBeanDefinition publisherAnnotationPostProcessorDef = new RootBeanDefinition(
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".aop.PublisherAnnotationBeanPostProcessor");
|
||||
publisherAnnotationPostProcessorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
String defaultPublisherChannel = element.getAttribute("default-publisher-channel");
|
||||
if (StringUtils.hasText(defaultPublisherChannel)) {
|
||||
publisherAnnotationPostProcessorDef.getPropertyValues().add("defaultChannel", new RuntimeBeanReference(defaultPublisherChannel));
|
||||
}
|
||||
String publisherAnnotationPostProcessorName = IntegrationNamespaceUtils.BASE_PACKAGE + ".internalPublisherAnnotationBeanPostProcessor";
|
||||
parserContext.getRegistry().registerBeanDefinition(publisherAnnotationPostProcessorName, publisherAnnotationPostProcessorDef);
|
||||
public BeanDefinition parse(final Element element, ParserContext parserContext) {
|
||||
new IntegrationRegistrar().registerBeanDefinitions(new StandardAnnotationMetadata(Object.class) {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
||||
return Collections.<String, Object> singletonMap("defaultPublisherChannel", element.getAttribute("default-publisher-channel"));
|
||||
}
|
||||
}, parserContext.getRegistry());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -25,6 +25,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -42,8 +43,6 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
final class ChannelInitializer implements BeanFactoryAware, InitializingBean {
|
||||
|
||||
public static String AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME = "$autoCreateChannelCandidates";
|
||||
|
||||
private Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
@@ -66,9 +65,8 @@ final class ChannelInitializer implements BeanFactoryAware, InitializingBean {
|
||||
}
|
||||
else {
|
||||
AutoCreateCandidatesCollector channelCandidatesCollector =
|
||||
beanFactory.getBean(AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME, AutoCreateCandidatesCollector.class);
|
||||
Assert.notNull(channelCandidatesCollector, "Failed to locate '" +
|
||||
ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
beanFactory.getBean(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME, AutoCreateCandidatesCollector.class);
|
||||
Assert.notNull(channelCandidatesCollector, "Failed to locate '" + IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
// at this point channelNames are all resolved with placeholders and SpEL
|
||||
Collection<String> channelNames = channelCandidatesCollector.getChannelNames();
|
||||
if (channelNames != null){
|
||||
@@ -98,5 +96,7 @@ final class ChannelInitializer implements BeanFactoryAware, InitializingBean {
|
||||
public Collection<String> getChannelNames() {
|
||||
return channelNames;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Properties;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.metadata.MetadataStore;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
@@ -51,6 +52,20 @@ public abstract class IntegrationContextUtils {
|
||||
|
||||
public static final String INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME = "integrationGlobalProperties";
|
||||
|
||||
public static final String CHANNEL_INITIALIZER_BEAN_NAME = "channelInitializer";
|
||||
|
||||
public static final String AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME = "$autoCreateChannelCandidates";
|
||||
|
||||
public static final String DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME = "DefaultConfiguringBeanFactoryPostProcessor";
|
||||
|
||||
public static final String MESSAGING_ANNOTATION_POSTPROCESSOR_NAME = IntegrationNamespaceUtils.BASE_PACKAGE
|
||||
+ ".internalMessagingAnnotationPostProcessor";
|
||||
|
||||
public static final String PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME = IntegrationNamespaceUtils.BASE_PACKAGE +
|
||||
".internalPublisherAnnotationBeanPostProcessor";
|
||||
|
||||
// public static final String FLOW_POST_PROCESSOR_BEAN_NAME = IntegrationFlowBeanFactoryPostProcessor.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* @param beanFactory BeanFactory for lookup, must not be null.
|
||||
* @return The {@link MetadataStore} bean whose name is "metadataStore".
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.configuration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.annotation.MessageEndpoint;
|
||||
import org.springframework.integration.annotation.Payload;
|
||||
import org.springframework.integration.annotation.Publisher;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.annotation.EnableIntegration;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @since 4.0
|
||||
*/
|
||||
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class EnableIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private MessageChannel input;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel output;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel publishedChannel;
|
||||
|
||||
@Test
|
||||
public void testAnnotatedServiceActivator() {
|
||||
this.input.send(MessageBuilder.withPayload("Foo").build());
|
||||
Message<?> receive = this.output.receive(1000);
|
||||
assertNotNull(receive);
|
||||
assertEquals("FOO", receive.getPayload());
|
||||
|
||||
receive = this.publishedChannel.receive(1000);
|
||||
assertNotNull(receive);
|
||||
assertEquals("foo", receive.getPayload());
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses = EnableIntegrationTests.class)
|
||||
@EnableIntegration
|
||||
public static class ContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public MessageChannel input() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel output() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel publishedChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@MessageEndpoint
|
||||
public static class AnnotationTestService {
|
||||
|
||||
@ServiceActivator(inputChannel = "input", outputChannel = "output")
|
||||
@Publisher(channel = "publishedChannel")
|
||||
@Payload("#args[0].toLowerCase()")
|
||||
public String handle(String payload) {
|
||||
return payload.toUpperCase();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -318,4 +318,32 @@
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Configuration</title>
|
||||
<para>
|
||||
Throughout this document you will see references to XML namespace support for declaring elements in a Spring
|
||||
Integration flow. This support is provided by a series of namespace parsers that generate appropriate
|
||||
bean definitions to implement a particular component. For example, many endpoints consist of a
|
||||
<interfacename>MessageHandler</interfacename> bean and a <classname>ConsumerEndpointFactoryBean</classname>
|
||||
into which the handler and an input channel name are injected.
|
||||
</para>
|
||||
<para>
|
||||
The first time a Spring Integration namespace element is encountered, the framework automatically declares
|
||||
a number of beans that are used to support the runtime environment (task scheduler,
|
||||
implicit channel creator, etc).
|
||||
</para>
|
||||
<para id="enable-integration">
|
||||
Starting with <emphasis>version 4.0</emphasis>, these support beans can also be defined when using
|
||||
<code>@Configuration</code> classes, by adding a new annotation <code>@EnableIntegration</code>.
|
||||
This is useful when declaring a simple Spring Integration flow using purely Java Configuration.
|
||||
For example; you can declare an endpoint with a <interfacename>MessageHandler</interfacename> <code>@Bean</code>
|
||||
as well as a <classname>ConsumerEndpointFactoryBean</classname> <code>@Bean</code>.
|
||||
</para>
|
||||
<para>
|
||||
<code>@EnableIntegration</code> is also useful when you have a parent context with no Spring Integration
|
||||
components and 2 or more child contexts that do use Spring Integration. It would enable these common
|
||||
components to be declared once only, in the parent context.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -23,15 +23,26 @@
|
||||
|
||||
<section id="4.0-general">
|
||||
<title>General Changes</title>
|
||||
<para>
|
||||
Core messaging abstractions (<interfacename>Message</interfacename>,
|
||||
<interfacename>MessageChannel</interfacename> etc) have moved to the Spring
|
||||
Framework <code>spring-messaging</code> module. Users who reference these
|
||||
classes directly in their code will need to make changes as described in
|
||||
the first section of the
|
||||
<ulink url="https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-3.0-to-4.0-Migration-Guide"
|
||||
>Migration Guide</ulink>.
|
||||
</para>
|
||||
<section>
|
||||
<title>Requires Spring Framework 4.0</title>
|
||||
<para>
|
||||
Core messaging abstractions (<interfacename>Message</interfacename>,
|
||||
<interfacename>MessageChannel</interfacename> etc) have moved to the Spring
|
||||
Framework <code>spring-messaging</code> module. Users who reference these
|
||||
classes directly in their code will need to make changes as described in
|
||||
the first section of the
|
||||
<ulink url="https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-3.0-to-4.0-Migration-Guide"
|
||||
>Migration Guide</ulink>.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>@EnableConfiguration</title>
|
||||
<para>
|
||||
The <code>@EnableIntegration</code> annotation has been added, to permit declaration of
|
||||
standard Spring Integration beans when using <code>@Configuration</code> classes. See
|
||||
<xref linkend="enable-integration"/> for more information.
|
||||
</para>
|
||||
</section>
|
||||
<section id="4.0-xpath-header-enricher-header-type">
|
||||
<title>Header Type for XPath Header Enricher</title>
|
||||
<para>
|
||||
|
||||
Reference in New Issue
Block a user