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.

Rather than trying to rework how AopConfigUtils works, a @PostConstruct
method has been added to ProxyTransactionManagementConfiguration to call
the usual AopConfigUtils registration methods.

Issue: SPR-8411, SPR-8494
This commit is contained in:
Chris Beams 2011-07-07 22:37:28 +00:00
parent 5aa24af126
commit f1ef3e4dcd
3 changed files with 63 additions and 9 deletions

View File

@ -22,6 +22,7 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -32,9 +33,14 @@ import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.config.AdviceMode;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
@ -152,6 +158,38 @@ public class EnableTransactionManagementIntegrationTests {
assertThat(txManager2.rollbacks, equalTo(0));
}
@Test
public void apcEscalation() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(EnableTxAndCachingConfig.class);
ctx.refresh();
}
@Configuration
@EnableTransactionManagement
@ImportResource("org/springframework/transaction/annotation/enable-caching.xml")
static class EnableTxAndCachingConfig {
@Bean
public PlatformTransactionManager txManager() {
return new CallCountingTransactionManager();
}
@Bean
public FooRepository fooRepository() {
return new DummyFooRepository();
}
@Bean
public CacheManager cacheManager() {
SimpleCacheManager mgr = new SimpleCacheManager();
ArrayList<Cache> caches = new ArrayList<Cache>();
caches.add(new ConcurrentMapCache());
mgr.setCaches(caches);
return mgr;
}
}
@Configuration
@EnableTransactionManagement

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven/>
</beans>

View File

@ -16,9 +16,12 @@
package org.springframework.transaction.annotation;
import javax.annotation.PostConstruct;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
@ -39,6 +42,17 @@ import org.springframework.transaction.interceptor.TransactionInterceptor;
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Autowired
private DefaultListableBeanFactory registry;
@PostConstruct
public void registerAutoProxyCreator() {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean)enableTx.get("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}
@Bean(name=TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
@ -67,12 +81,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;
}
}