diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachingConfigurationSelector.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachingConfigurationSelector.java index db194c1d4f7..df8be605cc1 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachingConfigurationSelector.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/CachingConfigurationSelector.java @@ -16,61 +16,37 @@ package org.springframework.cache.annotation; -import java.util.Map; - -import org.springframework.aop.config.AopConfigUtils; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.AdviceMode; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportSelectorContext; -import org.springframework.context.annotation.ImportSelector; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.util.Assert; +import org.springframework.context.annotation.AdviceModeImportSelector; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.context.annotation.AutoProxyRegistrar; /** * Selects which implementation of {@link AbstractCachingConfiguration} should be used - * based on the value of {@link EnableCaching#mode} on the importing @{@link Configuration} + * based on the value of {@link EnableCaching#mode} on the importing {@code @Configuration} * class. * * @author Chris Beams * @since 3.1 * @see EnableCaching - * @see AbstractCachingConfiguration * @see ProxyCachingConfiguration - * @see org.springframework.cache.aspectj.AspectJCachingConfiguration + * @see AnnotationConfigUtils.CACHE_ASPECT_CONFIGURATION_CLASS_NAME */ -public class CachingConfigurationSelector implements ImportSelector { +public class CachingConfigurationSelector extends AdviceModeImportSelector { /** * {@inheritDoc} - *

This implementation selects {@link ProxyCachingConfiguration} if - * {@link EnableCaching#mode()} equals {@code PROXY}, and otherwise selects - * {@link org.springframework.cache.aspectj.AspectJCachingConfiguration AspectJCacheConfiguration}. - *

If {@code #mode()} equals {@code PROXY}, an auto-proxy creator bean definition - * will also be added to the enclosing {@link BeanDefinitionRegistry} and escalated - * if necessary through the usual {@link AopConfigUtils} family of methods. + * @return {@link ProxyCachingConfiguration} or {@code AspectJCacheConfiguration} for + * {@code PROXY} and {@code ASPECTJ} values of {@link EnableCaching#mode()}, respectively */ - public String[] selectImports(ImportSelectorContext context) { - AnnotationMetadata importingClassMetadata = context.getImportingClassMetadata(); - BeanDefinitionRegistry registry = context.getBeanDefinitionRegistry(); - - Map enableCaching = - importingClassMetadata.getAnnotationAttributes(EnableCaching.class.getName()); - Assert.notNull(enableCaching, - "@EnableCaching is not present on importing class " + - importingClassMetadata.getClassName()); - - switch ((AdviceMode) enableCaching.get("mode")) { + public String[] selectImports(AdviceMode adviceMode) { + switch (adviceMode) { case PROXY: - AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); - if ((Boolean)enableCaching.get("proxyTargetClass")) { - AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); - } - return new String[] { ProxyCachingConfiguration.class.getName() }; + return new String[] { AutoProxyRegistrar.class.getName(), ProxyCachingConfiguration.class.getName() }; case ASPECTJ: - return new String[] {"org.springframework.cache.aspectj.AspectJCachingConfiguration"}; + return new String[] { AnnotationConfigUtils.CACHE_ASPECT_CONFIGURATION_CLASS_NAME }; default: - throw new IllegalArgumentException("Unknown AdviceMode " + enableCaching.get("mode")); + return null; } } diff --git a/org.springframework.context/src/main/java/org/springframework/cache/annotation/ProxyCachingConfiguration.java b/org.springframework.context/src/main/java/org/springframework/cache/annotation/ProxyCachingConfiguration.java index 476590beac2..2487ab6547d 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/annotation/ProxyCachingConfiguration.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/annotation/ProxyCachingConfiguration.java @@ -21,8 +21,10 @@ import org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvi import org.springframework.cache.interceptor.CacheInterceptor; import org.springframework.cache.interceptor.CacheOperationSource; import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.context.annotation.AutoProxyRegistrar; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Role; /** diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java new file mode 100644 index 00000000000..ecfa675a752 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AdviceModeImportSelector.java @@ -0,0 +1,107 @@ + /* + * Copyright 2002-2011 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.context.annotation; + +import java.lang.annotation.Annotation; +import java.util.Map; + +import org.springframework.core.GenericTypeResolver; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.Assert; + +/** + * Convenient base class for {@link ImportSelector} implementations that select imports + * based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*} + * annotations). + * + * @param Annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode + * attribute} + * + * @author Chris Beams + * @since 3.1 + */ +public abstract class AdviceModeImportSelector implements ImportSelector { + + public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode"; + + /** + * The name of the {@link AdviceMode} attribute for the annotation specified by the + * generic type {@code A}. The default is {@value #DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME}, + * but subclasses may override in order to customize. + */ + protected String getAdviceModeAttributeName() { + return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME; + } + + /** + * {@inheritDoc} + * + *

This implementation resolves the type of annotation from generic metadata and + * validates that (a) the annotation is in fact present on the importing + * {@code @Configuration} class and (b) that the given annotation has an + * {@linkplain #getAdviceModeAttributeName() advice mode attribute} of type + * {@link AdviceMode}. + * + *

The {@link #selectImports(AdviceMode)} method is then invoked, allowing the + * concrete implementation to choose imports in a safe and convenient fashion. + * + * @throws IllegalArgumentException if expected annotation {@code A} is not present + * on the importing {@code @Configuration} class or if {@link #selectImports(AdviceMode)} + * returns {@code null} + */ + public final String[] selectImports(AnnotationMetadata importingClassMetadata) { + Class annoType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class); + + Map attributes = importingClassMetadata.getAnnotationAttributes(annoType.getName()); + Assert.notNull(attributes, String.format( + "@%s is not present on importing class '%s' as expected", + annoType.getSimpleName(), importingClassMetadata.getClassName())); + + String modeAttrName = getAdviceModeAttributeName(); + Assert.hasText(modeAttrName); + + Object adviceMode = attributes.get(modeAttrName); + Assert.notNull(adviceMode, String.format( + "Advice mode attribute @%s#%s() does not exist", + annoType.getSimpleName(), modeAttrName)); + + Assert.isInstanceOf(AdviceMode.class, adviceMode, String.format( + "Incorrect type for advice mode attribute '@%s#%s()': ", + annoType.getSimpleName(), modeAttrName)); + + String[] imports = selectImports((AdviceMode) adviceMode); + Assert.notNull(imports, String.format("Unknown AdviceMode: '%s'", adviceMode)); + + return imports; + } + + /** + * Determine which classes should be imported based on the given {@code AdviceMode}. + * + *

Returning {@code null} from this method indicates that the {@code AdviceMode} could + * not be handled or was unknown and that an {@code IllegalArgumentException} should + * be thrown. + * + * @param adviceMode the value of the {@linkplain #getAdviceModeAttributeName() + * advice mode attribute} for the annotation specified via generics. + * + * @return array containing classes to import; empty array if none, {@code null} if + * the given {@code AdviceMode} is unknown. + */ + protected abstract String[] selectImports(AdviceMode adviceMode); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index 19f7ded835f..42a053c2d3c 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -119,6 +119,12 @@ public class AnnotationConfigUtils { public static final String CACHE_ASPECT_CLASS_NAME = "org.springframework.cache.aspectj.AnnotationCacheAspect"; + /** + * The name of the AspectJ caching aspect @{@code Configuration} class. + */ + public static final String CACHE_ASPECT_CONFIGURATION_CLASS_NAME = + "org.springframework.cache.aspectj.AspectJCachingConfiguration"; + /** * The bean name of the internally managed JPA annotation processor. */ diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyConfigurationSelector.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java similarity index 79% rename from org.springframework.context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyConfigurationSelector.java rename to org.springframework.context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java index 6b60c7ecab5..3cb2f2448f6 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyConfigurationSelector.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AspectJAutoProxyRegistrar.java @@ -31,15 +31,15 @@ import org.springframework.core.type.AnnotationMetadata; * @see EnableAspectJAutoProxy * @since 3.1 */ -public class AspectJAutoProxyConfigurationSelector implements ImportSelector { +class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { /** - * Register, escalate, and configure the AspectJ auto proxy creator. Always return - * an empty array, as no actual {@code @Configuration} classes are required. + * Register, escalate, and configure the AspectJ auto proxy creator based on the value + * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing + * {@code @Configuration} class. */ - public String[] selectImports(ImportSelectorContext context) { - BeanDefinitionRegistry registry = context.getBeanDefinitionRegistry(); - AnnotationMetadata importingClassMetadata = context.getImportingClassMetadata(); + public void registerBeanDefinitions( + AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Map enableAJAutoProxy = importingClassMetadata.getAnnotationAttributes(EnableAspectJAutoProxy.class.getName()); @@ -49,8 +49,6 @@ public class AspectJAutoProxyConfigurationSelector implements ImportSelector { if ((Boolean)enableAJAutoProxy.get("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } - - return new String[] { }; } } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AutoProxyRegistrar.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AutoProxyRegistrar.java new file mode 100644 index 00000000000..f83fb781a0b --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AutoProxyRegistrar.java @@ -0,0 +1,72 @@ +package org.springframework.context.annotation; + +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.aop.config.AopConfigUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.core.type.AnnotationMetadata; + +/** + * Registers an auto proxy creator against the current {@link BeanDefinitionRegistry} + * as appropriate based on an {@code @Enable*} annotation having {@code mode} and + * {@code proxyTargetClass} attributes set to the correct values. + * + * @author Chris Beams + * @see EnableAspectJAutoProxy + * @since 3.1 + */ +public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { + + private final Log logger = LogFactory.getLog(getClass()); + + /** + * Register, escalate, and configure the standard auto proxy creator (APC) against the + * given registry. Works by finding the nearest annotation declared on the importing + * {@code @Configuration} class that has both {@code mode} and {@code proxyTargetClass} + * attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if + * {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use + * subclass (CGLIB) proxying. + * + *

Several {@code @Enable*} annotations expose both {@code mode} and + * {@code proxyTargetClass} attributes. It is important to note that most of these + * capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME + * single APC}. For this reason, this implementation doesn't "care" exactly which + * annotation it finds -- as long as it exposes the right {@code mode} and + * {@code proxyTargetClass} attributes, the APC can be registered and configured all + * the same. + */ + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + boolean candidateFound = false; + Set annoTypes = importingClassMetadata.getAnnotationTypes(); + for (String annoType : annoTypes) { + Map candidate = importingClassMetadata.getAnnotationAttributes(annoType); + Object mode = candidate.get("mode"); + Object proxyTargetClass = candidate.get("proxyTargetClass"); + if (mode != null && proxyTargetClass != null + && mode.getClass().equals(AdviceMode.class) + && proxyTargetClass.getClass().equals(Boolean.class)) { + candidateFound = true; + if (mode == AdviceMode.PROXY) { + AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); + if ((Boolean)proxyTargetClass) { + AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); + } + } + } + } + if (!candidateFound) { + String name = getClass().getSimpleName(); + logger.warn(String.format("%s was imported but no annotations were found " + + "having both 'mode' and 'proxyTargetClass' attributes of type " + + "AdviceMode and boolean respectively. This means that auto proxy " + + "creator registration and configuration may not have occured as " + + "intended, and components may not be proxied as expected. Check to " + + "ensure that %s has been @Import'ed on the same class where these " + + "annotations are declared; otherwise remove the import of %s " + + "altogether.", name, name, name)); + } + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index d029dd93ccf..1ed1d786df4 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -338,9 +338,9 @@ class ConfigurationClassBeanDefinitionReader { private static class InvalidConfigurationImportProblem extends Problem { public InvalidConfigurationImportProblem(String className, Resource resource, AnnotationMetadata metadata) { super(String.format("%s was @Import'ed but is not annotated with @Configuration " + - "nor does it declare any @Bean methods. Update the class to " + - "meet one of these requirements or do not attempt to @Import it.", className), - new Location(resource, metadata)); + "nor does it declare any @Bean methods; it does not implement ImportSelector " + + "or extend ImportBeanDefinitionRegistrar. Update the class to meet one of these requirements " + + "or do not attempt to @Import it.", className), new Location(resource, metadata)); } } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/EnableAspectJAutoProxy.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/EnableAspectJAutoProxy.java index 0316c288579..a4cf352a2b7 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/EnableAspectJAutoProxy.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/EnableAspectJAutoProxy.java @@ -100,8 +100,8 @@ import java.lang.annotation.Target; */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -@Import(AspectJAutoProxyConfigurationSelector.class) @Documented +@Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { /** @@ -110,4 +110,4 @@ public @interface EnableAspectJAutoProxy { */ boolean proxyTargetClass() default false; -} +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Import.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Import.java index ce0ea878583..4a2fe947ca8 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/Import.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Import.java @@ -26,15 +26,18 @@ import java.lang.annotation.Target; * Indicates one or more @{@link Configuration} classes to import. * *

Provides functionality equivalent to the {@code } element in Spring XML. - * Only supported for actual {@code @Configuration}-annotated classes and implementations - * of the {@link ImportSelector} interface. + * Only supported for classes annotated with {@code @Configuration} or declaring at least + * one {@link @Bean} method, as well as {@link ImportSelector} and + * {@link ImportBeanDefinitionRegistrar} implementations. * - *

@{@link Bean} definitions declared in imported {@code @Configuration} classes + *

@{@code Bean} definitions declared in imported {@code @Configuration} classes * should be accessed by using @{@link Autowired} injection. Either the bean itself can * be autowired, or the configuration class instance declaring the bean can be autowired. * The latter approach allows for explicit, IDE-friendly navigation between * {@code @Configuration} class methods. * + *

May be declared at the class level or as a meta-annotation. + * *

If XML or other non-{@code @Configuration} bean definition resources need to be * imported, use @{@link ImportResource} * @@ -44,7 +47,7 @@ import java.lang.annotation.Target; * @see ImportSelector * @see ImportResource */ -@Target({ElementType.TYPE}) +@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportBeanDefinitionRegistrar.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportBeanDefinitionRegistrar.java new file mode 100644 index 00000000000..21f29813a8f --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportBeanDefinitionRegistrar.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2011 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.context.annotation; + +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.core.type.AnnotationMetadata; + +/** + * Interface to be implemented by types that register additional bean definitions when + * processing @{@link Configuration} classes. Useful when operating at the bean definition + * level (as opposed to {@code @Bean} method/instance level) is desired or necessary. + * + *

Along with {@code @Configuration} and {@link ImportSelector}, classes of this type + * may be provided to the @{@link Import} annotation (or may also be returned from an + * {@code ImportSelector}). + * + *

See implementations and associated unit tests for usage examples. + * + * @author Chris Beams + * @since 3.1 + * @see Import + * @see ImportSelector + * @see Configuration + */ +public interface ImportBeanDefinitionRegistrar { + + /** + * Register bean definitions as necessary based on the given annotation metadata of + * the importing {@code @Configuration} class. + *

Note that {@link BeanDefinitionRegistryPostProcessor} types may not be + * registered here, due to lifecycle constraints related to {@code @Configuration} + * class processing. + * @param importingClassMetadata annotation metadata of the importing class + * @param registry current bean definition registry + */ + public void registerBeanDefinitions( + AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry); + +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportSelector.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportSelector.java index a4d8b61b706..802dde7083c 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportSelector.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportSelector.java @@ -16,30 +16,25 @@ package org.springframework.context.annotation; +import org.springframework.core.type.AnnotationMetadata; + /** * Interface to be implemented by types that determine which @{@link Configuration} * class(es) should be imported based on a given selection criteria, usually one or more * annotation attributes. * - *

In certain cases, an {@code ImportSelector} may register additional bean definitions - * through the {@code BeanDefinitionRegistry} available in the - * {@link ImportSelectorContext} provided to the {@link #selectImports} method. - * * @author Chris Beams * @since 3.1 * @see Import + * @see ImportBeanDefinitionRegistrar * @see Configuration */ public interface ImportSelector { /** * Select and return the names of which class(es) should be imported based on - * the {@code AnnotationMetadata} of the importing {@code @Configuration} class and - * optionally register any {@code BeanDefinition}s necessary to support the selected - * classes. - * @param context containing the {@code AnnotationMetadata} of the importing @{@link - * Configuration} class and the enclosing {@code BeanDefinitionRegistry}. + * the {@link AnnotationMetadata} of the importing @{@link Configuration} class. */ - String[] selectImports(ImportSelectorContext context); + String[] selectImports(AnnotationMetadata importingClassMetadata); } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportSelectorContext.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportSelectorContext.java deleted file mode 100644 index ef23c63f9c9..00000000000 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportSelectorContext.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.springframework.context.annotation; - -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.core.type.AnnotationMetadata; - -/** - * Context object holding the {@link AnnotationMetadata} of the @{@link Configuration} - * class that imported the current {@link ImportSelector} as well as the enclosing - * {@link BeanDefinitionRegistry} to allow for conditional bean definition - * registration when necessary. - * - * @author Chris Beams - * @since 3.1 - * @see Import - * @see ImportSelector - */ -public class ImportSelectorContext { - private final AnnotationMetadata importingClassMetadata; - private final BeanDefinitionRegistry registry; - - ImportSelectorContext(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - this.importingClassMetadata = importingClassMetadata; - this.registry = registry; - } - - public AnnotationMetadata getImportingClassMetadata() { - return this.importingClassMetadata; - } - - public BeanDefinitionRegistry getBeanDefinitionRegistry() { - return registry; - } -} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/AsyncConfigurationSelector.java b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/AsyncConfigurationSelector.java index 488d6599872..3815016c9e3 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/AsyncConfigurationSelector.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/AsyncConfigurationSelector.java @@ -16,52 +16,35 @@ package org.springframework.scheduling.annotation; -import java.util.Map; - import org.springframework.context.annotation.AdviceMode; +import org.springframework.context.annotation.AdviceModeImportSelector; import org.springframework.context.annotation.AnnotationConfigUtils; -import org.springframework.context.annotation.ImportSelectorContext; -import org.springframework.context.annotation.ImportSelector; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.util.Assert; /** - * Selects which implementation of {@link AbstractAsyncConfiguration} - * should be used based on the value of {@link EnableAsync#mode} on the - * importing @{@link Configuration} class. + * Selects which implementation of {@link AbstractAsyncConfiguration} should be used based + * on the value of {@link EnableAsync#mode} on the importing {@code @Configuration} class. * * @author Chris Beams * @since 3.1 * @see EnableAsync - * @see AbstractAsyncConfiguration * @see ProxyAsyncConfiguration * @see AnnotationConfigUtils#ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME */ -public class AsyncConfigurationSelector implements ImportSelector { +public class AsyncConfigurationSelector extends AdviceModeImportSelector { /** * {@inheritDoc} - *

This implementation selects {@link ProxyAsyncConfiguration} if - * {@link EnableAsync#mode()} equals {@code PROXY}, and otherwise selects - * {@link org.springframework.scheduling.aspectj.AspectJAsyncConfiguration - * AspectJAsyncConfiguration}. No additional {@code BeanDefinition}s are registered - * in either case. + * @return {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration} for + * {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()}, respectively */ - public String[] selectImports(ImportSelectorContext context) { - AnnotationMetadata importingClassMetadata = context.getImportingClassMetadata(); - Map enableAsync = - importingClassMetadata.getAnnotationAttributes(EnableAsync.class.getName()); - Assert.notNull(enableAsync, - "@EnableAsync is not present on importing class " + - importingClassMetadata.getClassName()); - - switch ((AdviceMode) enableAsync.get("mode")) { + public String[] selectImports(AdviceMode adviceMode) { + switch (adviceMode) { case PROXY: - return new String[] {ProxyAsyncConfiguration.class.getName()}; + return new String[] { ProxyAsyncConfiguration.class.getName() }; case ASPECTJ: - return new String[] {AnnotationConfigUtils.ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME}; + return new String[] { AnnotationConfigUtils.ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME }; default: - throw new IllegalArgumentException("Unknown AdviceMode " + enableAsync.get("mode")); + return null; } } diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurationSelector.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurationSelector.java index e26ac1c2470..a12be89d71d 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurationSelector.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurationSelector.java @@ -16,63 +16,42 @@ package org.springframework.transaction.annotation; -import java.util.Map; - -import org.springframework.aop.config.AopConfigUtils; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.AdviceMode; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportSelectorContext; -import org.springframework.context.annotation.ImportSelector; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.util.Assert; +import org.springframework.context.annotation.AdviceModeImportSelector; +import org.springframework.context.annotation.AutoProxyRegistrar; +import org.springframework.transaction.config.TransactionManagementConfigUtils; /** * Selects which implementation of {@link AbstractTransactionManagementConfiguration} * should be used based on the value of {@link EnableTransactionManagement#mode} on the - * importing @{@link Configuration} class. + * importing {@code @Configuration} class. * * @author Chris Beams * @since 3.1 * @see EnableTransactionManagement - * @see AbstractTransactionManagementConfiguration * @see ProxyTransactionManagementConfiguration - * @see org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration + * @see TransactionManagementConfigUtils#TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME */ -public class TransactionManagementConfigurationSelector implements ImportSelector { +public class TransactionManagementConfigurationSelector + extends AdviceModeImportSelector { /** * {@inheritDoc} - *

This implementation selects {@link ProxyTransactionManagementConfiguration} if - * {@link EnableTransactionManagement#mode()} equals {@code PROXY}, and otherwise selects - * {@link org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration - * AspectJTransactionManagementConfiguration}. - *

If {@code #mode()} equals {@code PROXY}, an auto-proxy creator bean definition - * will also be added to the enclosing {@link BeanDefinitionRegistry} and escalated - * if necessary through the usual {@link AopConfigUtils} family of methods. + * @return {@link ProxyTransactionManagementConfiguration} or + * {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and + * {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively */ - public String[] selectImports(ImportSelectorContext context) { - AnnotationMetadata importingClassMetadata = context.getImportingClassMetadata(); - BeanDefinitionRegistry registry = context.getBeanDefinitionRegistry(); - - Map enableTx = - importingClassMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName()); - Assert.notNull(enableTx, - "@EnableTransactionManagement is not present on importing class " + - importingClassMetadata.getClassName()); - - switch ((AdviceMode) enableTx.get("mode")) { + @Override + protected String[] selectImports(AdviceMode adviceMode) { + switch (adviceMode) { case PROXY: - AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); - if ((Boolean)enableTx.get("proxyTargetClass")) { - AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); - } - return new String[] { ProxyTransactionManagementConfiguration.class.getName() }; + return new String[] { AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName() }; case ASPECTJ: - return new String[] {"org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration"}; + return new String[] { TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME }; default: - throw new IllegalArgumentException("Unknown AdviceMode " + enableTx.get("mode")); + return null; } } + } diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TransactionManagementConfigUtils.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TransactionManagementConfigUtils.java index f2a613ed627..744a57ebf02 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TransactionManagementConfigUtils.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/config/TransactionManagementConfigUtils.java @@ -36,4 +36,10 @@ public abstract class TransactionManagementConfigUtils { public static final String TRANSACTION_ASPECT_CLASS_NAME = "org.springframework.transaction.aspectj.AnnotationTransactionAspect"; + /** + * The name of the AspectJ transaction management @{@code Configuration} class. + */ + public static final String TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME = + "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration"; + }