Fix APC registration for @EnableTransactionManagement
Prior to this change, @EnableTransactionManagement (via the ProxyTransactionManagementConfiguration class) did not properly register its auto-proxy creator through the usual AopConfigUtils methods. It was trying to register the APC as a normal @Bean method, but this causes issues (SPR-8494) with the logic in AopConfigUtils#registerOrEscalateApcAsRequired, which expects the APC bean definition to have a beanClassName property. When the APC is registered via a @Bean definition, it is actually a factoryBean/factoryMethod situation with no directly resolvable beanClass/beanClassName. To solve this problem, ImportSelector#selectImports has been refactored to accept an ImportSelector.Context instance. This object contains the AnnotationMetadata of the importing class as well as the enclosing BeanDefinitionRegistry to allow for the kind of conditional bean registration necessary here. In this case, the bean definition that must be registered conditionally is that of the auto-proxy creator. It should only be registered if AdviceMode == PROXY, and thus the ImportSelector is an appropriate place to make this happen. It must happen as a BeanDefinition (rather than a @Bean method) for compatibility with AopConfigUtils, and working with the BeanDefinitionRegistry API allows for that. This change does mean that in certain cases like this one, #selectImports has container modifying side effects. Documentation has been updated to reflect. Issue: SPR-8411, SPR-8494
This commit is contained in:
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.transaction.annotation;
|
||||
|
||||
import org.springframework.aop.config.AopConfigUtils;
|
||||
import org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -67,12 +65,4 @@ public class ProxyTransactionManagementConfiguration extends AbstractTransaction
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
// TODO: deal with escalation of APCs
|
||||
@Bean(name=AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public InfrastructureAdvisorAutoProxyCreator apc() {
|
||||
InfrastructureAdvisorAutoProxyCreator apc = new InfrastructureAdvisorAutoProxyCreator();
|
||||
apc.setProxyTargetClass((Boolean) this.enableTx.get("proxyTargetClass"));
|
||||
return apc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ 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.Configuration;
|
||||
import org.springframework.context.annotation.ImportSelector;
|
||||
import org.springframework.context.config.AdviceMode;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -38,12 +41,19 @@ import org.springframework.util.Assert;
|
||||
public class TransactionManagementConfigurationSelector implements ImportSelector {
|
||||
|
||||
/**
|
||||
* Import {@link ProxyTransactionManagementConfiguration} if {@link
|
||||
* EnableTransactionManagement#mode()} equals {@code PROXY}, otherwise import {@link
|
||||
* org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation selects {@link ProxyTransactionManagementConfiguration} if
|
||||
* {@link EnableTransactionManagement#mode()} equals {@code PROXY}, and otherwise selects
|
||||
* {@link org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration
|
||||
* AspectJTransactionManagementConfiguration}.
|
||||
* <p>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.
|
||||
*/
|
||||
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||
public String[] selectImports(ImportSelector.Context context) {
|
||||
AnnotationMetadata importingClassMetadata = context.getImportingClassMetadata();
|
||||
BeanDefinitionRegistry registry = context.getBeanDefinitionRegistry();
|
||||
|
||||
Map<String, Object> enableTx =
|
||||
importingClassMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName());
|
||||
Assert.notNull(enableTx,
|
||||
@@ -52,7 +62,11 @@ public class TransactionManagementConfigurationSelector implements ImportSelecto
|
||||
|
||||
switch ((AdviceMode) enableTx.get("mode")) {
|
||||
case PROXY:
|
||||
return new String[] {ProxyTransactionManagementConfiguration.class.getName()};
|
||||
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
|
||||
if ((Boolean)enableTx.get("proxyTargetClass")) {
|
||||
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
|
||||
}
|
||||
return new String[] { ProxyTransactionManagementConfiguration.class.getName() };
|
||||
case ASPECTJ:
|
||||
return new String[] {"org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration"};
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user