Introduce @EnableTransactionManagement
This commit is contained in:
parent
d9a89529f0
commit
01e5120a26
|
@ -72,6 +72,11 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
|
||||||
this.beanFactory = beanFactory;
|
this.beanFactory = beanFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAdvice(Advice advice) {
|
||||||
|
synchronized (this.adviceMonitor) {
|
||||||
|
this.advice = advice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Advice getAdvice() {
|
public Advice getAdvice() {
|
||||||
synchronized (this.adviceMonitor) {
|
synchronized (this.adviceMonitor) {
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.transaction.aspectj;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Role;
|
||||||
|
import org.springframework.transaction.annotation.AbstractTransactionManagementConfiguration;
|
||||||
|
import org.springframework.transaction.config.TransactionManagementConfigUtils;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class AspectJTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
|
||||||
|
|
||||||
|
@Bean(name=TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME)
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
public AnnotationTransactionAspect transactionAspect() {
|
||||||
|
AnnotationTransactionAspect txAspect = AnnotationTransactionAspect.aspectOf();
|
||||||
|
if (this.txManager != null) {
|
||||||
|
txAspect.setTransactionManager(this.txManager);
|
||||||
|
}
|
||||||
|
return txAspect;
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,9 +40,6 @@ import org.springframework.beans.factory.DisposableBean;
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Feature;
|
|
||||||
import org.springframework.context.annotation.FeatureConfiguration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.context.annotation.ImportResource;
|
import org.springframework.context.annotation.ImportResource;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
|
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
|
||||||
|
@ -53,8 +50,8 @@ import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBui
|
||||||
import org.springframework.orm.hibernate3.scannable.Foo;
|
import org.springframework.orm.hibernate3.scannable.Foo;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.config.TxAnnotationDriven;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration tests for configuring Hibernate SessionFactory types
|
* Integration tests for configuring Hibernate SessionFactory types
|
||||||
|
@ -201,7 +198,7 @@ public class HibernateSessionFactoryConfigurationTests {
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Import(TxConfig.class)
|
@EnableTransactionManagement
|
||||||
static class RepositoryConfig {
|
static class RepositoryConfig {
|
||||||
@Inject SessionFactory sessionFactory;
|
@Inject SessionFactory sessionFactory;
|
||||||
|
|
||||||
|
@ -227,15 +224,6 @@ public class HibernateSessionFactoryConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@FeatureConfiguration
|
|
||||||
static class TxConfig {
|
|
||||||
@Feature
|
|
||||||
TxAnnotationDriven tx(PlatformTransactionManager txManager) {
|
|
||||||
return new TxAnnotationDriven(txManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ImportResource("org/springframework/orm/hibernate3/AnnotationSessionFactoryBeanXmlConfig-context.xml")
|
@ImportResource("org/springframework/orm/hibernate3/AnnotationSessionFactoryBeanXmlConfig-context.xml")
|
||||||
static class AnnotationSessionFactoryBeanXmlConfig extends DataConfig {
|
static class AnnotationSessionFactoryBeanXmlConfig extends DataConfig {
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.springframework.transaction;
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2007 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.support.DefaultTransactionStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Rod Johnson
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
*/
|
||||||
|
public class CallCountingTransactionManager extends AbstractPlatformTransactionManager {
|
||||||
|
|
||||||
|
public TransactionDefinition lastDefinition;
|
||||||
|
public int begun;
|
||||||
|
public int commits;
|
||||||
|
public int rollbacks;
|
||||||
|
public int inflight;
|
||||||
|
|
||||||
|
protected Object doGetTransaction() {
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doBegin(Object transaction, TransactionDefinition definition) {
|
||||||
|
this.lastDefinition = definition;
|
||||||
|
++begun;
|
||||||
|
++inflight;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doCommit(DefaultTransactionStatus status) {
|
||||||
|
++commits;
|
||||||
|
--inflight;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doRollback(DefaultTransactionStatus status) {
|
||||||
|
++rollbacks;
|
||||||
|
--inflight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
begun = commits = rollbacks = inflight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* 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.transaction.annotation;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.aop.Advisor;
|
||||||
|
import org.springframework.aop.framework.Advised;
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.config.AdviceMode;
|
||||||
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.CallCountingTransactionManager;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for the @EnableTransactionManagement annotation.
|
||||||
|
*
|
||||||
|
* @author Chris Beams
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
public class EnableTransactionManagementIntegrationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void repositoryIsNotTxProxy() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(Config.class);
|
||||||
|
ctx.refresh();
|
||||||
|
|
||||||
|
try {
|
||||||
|
assertTxProxying(ctx);
|
||||||
|
fail("expected exception");
|
||||||
|
} catch (AssertionError ex) {
|
||||||
|
assertThat(ex.getMessage(), equalTo("FooRepository is not a TX proxy"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void repositoryIsTxProxy_withDefaultTxManagerName() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(Config.class, DefaultTxManagerNameConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
|
||||||
|
assertTxProxying(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void repositoryIsTxProxy_withCustomTxManagerName() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(Config.class, CustomTxManagerNameConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
|
||||||
|
assertTxProxying(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore @Test // TODO SPR-8207
|
||||||
|
public void repositoryIsTxProxy_withNonConventionalTxManagerName_fallsBackToByTypeLookup() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(Config.class, NonConventionalTxManagerNameConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
|
||||||
|
assertTxProxying(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void repositoryIsClassBasedTxProxy() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(Config.class, ProxyTargetClassTxConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
|
||||||
|
assertTxProxying(ctx);
|
||||||
|
assertThat(AopUtils.isCglibProxy(ctx.getBean(FooRepository.class)), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void repositoryUsesAspectJAdviceMode() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(Config.class, AspectJTxConfig.class);
|
||||||
|
try {
|
||||||
|
ctx.refresh();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// this test is a bit fragile, but gets the job done, proving that an
|
||||||
|
// attempt was made to look up the AJ aspect. It's due to classpath issues
|
||||||
|
// in .integration-tests that it's not found.
|
||||||
|
assertTrue(ex.getMessage().endsWith("AspectJTransactionManagementConfiguration.class] cannot be opened because it does not exist"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void implicitTxManager() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(ImplicitTxManagerConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
|
||||||
|
FooRepository fooRepository = ctx.getBean(FooRepository.class);
|
||||||
|
fooRepository.findAll();
|
||||||
|
|
||||||
|
CallCountingTransactionManager txManager = ctx.getBean(CallCountingTransactionManager.class);
|
||||||
|
assertThat(txManager.begun, equalTo(1));
|
||||||
|
assertThat(txManager.commits, equalTo(1));
|
||||||
|
assertThat(txManager.rollbacks, equalTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void explicitTxManager() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(ExplicitTxManagerConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
|
||||||
|
FooRepository fooRepository = ctx.getBean(FooRepository.class);
|
||||||
|
fooRepository.findAll();
|
||||||
|
|
||||||
|
CallCountingTransactionManager txManager1 = ctx.getBean("txManager1", CallCountingTransactionManager.class);
|
||||||
|
assertThat(txManager1.begun, equalTo(1));
|
||||||
|
assertThat(txManager1.commits, equalTo(1));
|
||||||
|
assertThat(txManager1.rollbacks, equalTo(0));
|
||||||
|
|
||||||
|
CallCountingTransactionManager txManager2 = ctx.getBean("txManager2", CallCountingTransactionManager.class);
|
||||||
|
assertThat(txManager2.begun, equalTo(0));
|
||||||
|
assertThat(txManager2.commits, equalTo(0));
|
||||||
|
assertThat(txManager2.rollbacks, equalTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
static class ImplicitTxManagerConfig {
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager txManager() {
|
||||||
|
return new CallCountingTransactionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FooRepository fooRepository() {
|
||||||
|
return new DummyFooRepository();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
static class ExplicitTxManagerConfig implements TransactionManagementConfigurer {
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager txManager1() {
|
||||||
|
return new CallCountingTransactionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager txManager2() {
|
||||||
|
return new CallCountingTransactionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlatformTransactionManager createTransactionManager() {
|
||||||
|
return txManager1();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FooRepository fooRepository() {
|
||||||
|
return new DummyFooRepository();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertTxProxying(AnnotationConfigApplicationContext ctx) {
|
||||||
|
FooRepository repo = ctx.getBean(FooRepository.class);
|
||||||
|
|
||||||
|
boolean isTxProxy = false;
|
||||||
|
if (AopUtils.isAopProxy(repo)) {
|
||||||
|
for (Advisor advisor : ((Advised)repo).getAdvisors()) {
|
||||||
|
if (advisor instanceof BeanFactoryTransactionAttributeSourceAdvisor) {
|
||||||
|
isTxProxy = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue("FooRepository is not a TX proxy", isTxProxy);
|
||||||
|
|
||||||
|
// trigger a transaction
|
||||||
|
repo.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
static class DefaultTxManagerNameConfig {
|
||||||
|
@Bean
|
||||||
|
PlatformTransactionManager transactionManager(DataSource dataSource) {
|
||||||
|
return new DataSourceTransactionManager(dataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
static class CustomTxManagerNameConfig {
|
||||||
|
@Bean
|
||||||
|
PlatformTransactionManager txManager(DataSource dataSource) {
|
||||||
|
return new DataSourceTransactionManager(dataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
static class NonConventionalTxManagerNameConfig {
|
||||||
|
@Bean
|
||||||
|
PlatformTransactionManager txManager(DataSource dataSource) {
|
||||||
|
return new DataSourceTransactionManager(dataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement(proxyTargetClass=true)
|
||||||
|
static class ProxyTargetClassTxConfig {
|
||||||
|
@Bean
|
||||||
|
PlatformTransactionManager transactionManager(DataSource dataSource) {
|
||||||
|
return new DataSourceTransactionManager(dataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
|
||||||
|
static class AspectJTxConfig {
|
||||||
|
@Bean
|
||||||
|
PlatformTransactionManager transactionManager(DataSource dataSource) {
|
||||||
|
return new DataSourceTransactionManager(dataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class Config {
|
||||||
|
@Bean
|
||||||
|
FooRepository fooRepository() {
|
||||||
|
JdbcFooRepository repos = new JdbcFooRepository();
|
||||||
|
repos.setDataSource(dataSource());
|
||||||
|
return repos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
DataSource dataSource() {
|
||||||
|
return new EmbeddedDatabaseBuilder()
|
||||||
|
.setType(EmbeddedDatabaseType.HSQL)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface FooRepository {
|
||||||
|
List<Object> findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
static class JdbcFooRepository implements FooRepository {
|
||||||
|
|
||||||
|
public void setDataSource(DataSource dataSource) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<Object> findAll() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
static class DummyFooRepository implements FooRepository {
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<Object> findAll() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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.transaction.annotation;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.ImportAware;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class providing common structure for enabling Spring's annotation-
|
||||||
|
* driven transaction management capability.
|
||||||
|
*
|
||||||
|
* @author Chris Beams
|
||||||
|
* @since 3.1
|
||||||
|
* @see EnableTransactionManagement
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
|
||||||
|
|
||||||
|
protected Map<String, Object> enableTx;
|
||||||
|
protected PlatformTransactionManager txManager;
|
||||||
|
|
||||||
|
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||||
|
enableTx = importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false);
|
||||||
|
Assert.notNull(enableTx,
|
||||||
|
"@EnableTransactionManagement is not present on importing class " +
|
||||||
|
importMetadata.getClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired(required=false)
|
||||||
|
void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
|
||||||
|
if (configurers == null || configurers.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurers.size() > 1) {
|
||||||
|
throw new IllegalStateException("only one TransactionManagementConfigurer may exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionManagementConfigurer configurer = configurers.iterator().next();
|
||||||
|
this.txManager = configurer.createTransactionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.transaction.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.context.config.AdviceMode;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Import(TransactionManagementConfigurationSelector.class)
|
||||||
|
public @interface EnableTransactionManagement {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate whether class-based (CGLIB) proxies are to be created as opposed
|
||||||
|
* to standard Java interface-based proxies. The default is {@code false}.
|
||||||
|
*
|
||||||
|
* <p>Note: Class-based proxies require the {@link Transactional @Transactional}
|
||||||
|
* annotation to be defined on the concrete class. Annotations in interfaces will
|
||||||
|
* not work in that case (they will rather only work with interface-based proxies)!
|
||||||
|
*/
|
||||||
|
boolean proxyTargetClass() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate how transactional advice should be applied.
|
||||||
|
* The default is {@link AdviceMode.PROXY}.
|
||||||
|
* @see AdviceMode
|
||||||
|
*/
|
||||||
|
AdviceMode mode() default AdviceMode.PROXY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate the ordering of the execution of the transaction advisor
|
||||||
|
* when multiple advices are applied at a specific joinpoint.
|
||||||
|
* The default is to not explicitly order the advisor.
|
||||||
|
*/
|
||||||
|
int order() default Ordered.NOT_ORDERED;
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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.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;
|
||||||
|
import org.springframework.context.annotation.Role;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.transaction.config.TransactionManagementConfigUtils;
|
||||||
|
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
|
||||||
|
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||||
|
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
|
||||||
|
|
||||||
|
@Bean(name=TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
|
||||||
|
BeanFactoryTransactionAttributeSourceAdvisor advisor =
|
||||||
|
new BeanFactoryTransactionAttributeSourceAdvisor();
|
||||||
|
advisor.setTransactionAttributeSource(transactionAttributeSource());
|
||||||
|
advisor.setAdvice(transactionInterceptor());
|
||||||
|
int order = (Integer)this.enableTx.get("order");
|
||||||
|
if (order != Ordered.NOT_ORDERED) {
|
||||||
|
advisor.setOrder(order);
|
||||||
|
}
|
||||||
|
return advisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
public TransactionAttributeSource transactionAttributeSource() {
|
||||||
|
return new AnnotationTransactionAttributeSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
public TransactionInterceptor transactionInterceptor() {
|
||||||
|
TransactionInterceptor interceptor = new TransactionInterceptor();
|
||||||
|
interceptor.setTransactionAttributeSource(transactionAttributeSource());
|
||||||
|
if (this.txManager != null) {
|
||||||
|
interceptor.setTransactionManager(this.txManager);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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.transaction.annotation;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ImportSelector;
|
||||||
|
import org.springframework.context.config.AdviceMode;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
public class TransactionManagementConfigurationSelector implements ImportSelector {
|
||||||
|
|
||||||
|
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
|
||||||
|
Map<String, Object> enableTx =
|
||||||
|
importingClassMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName());
|
||||||
|
Assert.notNull(enableTx,
|
||||||
|
"@EnableTransactionManagement is not present on importing class " +
|
||||||
|
importingClassMetadata.getClassName());
|
||||||
|
|
||||||
|
switch ((AdviceMode) enableTx.get("mode")) {
|
||||||
|
case PROXY:
|
||||||
|
return new String[] {ProxyTransactionManagementConfiguration.class.getName()};
|
||||||
|
case ASPECTJ:
|
||||||
|
return new String[] {"org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration"};
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown AdviceMode " + enableTx.get("mode"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.transaction.annotation;
|
||||||
|
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
public interface TransactionManagementConfigurer {
|
||||||
|
|
||||||
|
PlatformTransactionManager createTransactionManager();
|
||||||
|
|
||||||
|
}
|
|
@ -26,10 +26,9 @@ import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.context.config.AbstractSpecificationBeanDefinitionParser;
|
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||||
import org.springframework.context.config.FeatureSpecification;
|
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
|
||||||
import org.springframework.transaction.annotation.TransactionManagementCapability;
|
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||||
import org.w3c.dom.Element;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser
|
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser
|
||||||
|
@ -53,20 +52,20 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
/**
|
/**
|
||||||
* The bean name of the internally managed transaction advisor (mode="proxy").
|
* The bean name of the internally managed transaction advisor (mode="proxy").
|
||||||
* @deprecated as of Spring 3.1 in favor of
|
* @deprecated as of Spring 3.1 in favor of
|
||||||
* {@link TransactionManagementCapability#TRANSACTION_ADVISOR_BEAN_NAME}
|
* {@link TransactionManagementConfigUtils#TRANSACTION_ADVISOR_BEAN_NAME}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final String TRANSACTION_ADVISOR_BEAN_NAME =
|
public static final String TRANSACTION_ADVISOR_BEAN_NAME =
|
||||||
TransactionManagementCapability.TRANSACTION_ADVISOR_BEAN_NAME;
|
TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The bean name of the internally managed transaction aspect (mode="aspectj").
|
* The bean name of the internally managed transaction aspect (mode="aspectj").
|
||||||
* @deprecated as of Spring 3.1 in favor of
|
* @deprecated as of Spring 3.1 in favor of
|
||||||
* {@link TransactionManagementCapability#TRANSACTION_ASPECT_BEAN_NAME}
|
* {@link TransactionManagementConfigUtils#TRANSACTION_ASPECT_BEAN_NAME}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final String TRANSACTION_ASPECT_BEAN_NAME =
|
public static final String TRANSACTION_ASPECT_BEAN_NAME =
|
||||||
TransactionManagementCapability.TRANSACTION_ASPECT_BEAN_NAME;
|
TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,12 +73,81 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||||
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
|
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
|
||||||
* with the container as necessary.
|
* with the container as necessary.
|
||||||
*/
|
*/
|
||||||
@Override
|
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||||
protected FeatureSpecification doParse(Element element, ParserContext parserContext) {
|
String mode = element.getAttribute("mode");
|
||||||
return new TxAnnotationDriven(element.getAttribute("transaction-manager"))
|
if ("aspectj".equals(mode)) {
|
||||||
.order(element.getAttribute("order"))
|
// mode="aspectj"
|
||||||
.mode(element.getAttribute("mode"))
|
registerTransactionAspect(element, parserContext);
|
||||||
.proxyTargetClass(Boolean.valueOf(element.getAttribute("proxy-target-class")));
|
}
|
||||||
|
else {
|
||||||
|
// mode="proxy"
|
||||||
|
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerTransactionAspect(Element element, ParserContext parserContext) {
|
||||||
|
String txAspectBeanName = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME;
|
||||||
|
String txAspectClassName = TransactionManagementConfigUtils.TRANSACTION_ASPECT_CLASS_NAME;
|
||||||
|
if (!parserContext.getRegistry().containsBeanDefinition(txAspectBeanName)) {
|
||||||
|
RootBeanDefinition def = new RootBeanDefinition();
|
||||||
|
def.setBeanClassName(txAspectClassName);
|
||||||
|
def.setFactoryMethodName("aspectOf");
|
||||||
|
registerTransactionManager(element, def);
|
||||||
|
parserContext.registerBeanComponent(new BeanComponentDefinition(def, txAspectBeanName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerTransactionManager(Element element, BeanDefinition def) {
|
||||||
|
def.getPropertyValues().add("transactionManagerBeanName",
|
||||||
|
TxNamespaceHandler.getTransactionManagerName(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
|
||||||
|
*/
|
||||||
|
private static class AopAutoProxyConfigurer {
|
||||||
|
|
||||||
|
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
|
||||||
|
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||||
|
|
||||||
|
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
|
||||||
|
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
|
||||||
|
Object eleSource = parserContext.extractSource(element);
|
||||||
|
|
||||||
|
// Create the TransactionAttributeSource definition.
|
||||||
|
RootBeanDefinition sourceDef = new RootBeanDefinition(AnnotationTransactionAttributeSource.class);
|
||||||
|
sourceDef.setSource(eleSource);
|
||||||
|
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
|
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
|
||||||
|
|
||||||
|
// Create the TransactionInterceptor definition.
|
||||||
|
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
|
||||||
|
interceptorDef.setSource(eleSource);
|
||||||
|
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
|
registerTransactionManager(element, interceptorDef);
|
||||||
|
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
|
||||||
|
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
|
||||||
|
|
||||||
|
// Create the TransactionAttributeSourceAdvisor definition.
|
||||||
|
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
|
||||||
|
advisorDef.setSource(eleSource);
|
||||||
|
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||||
|
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
|
||||||
|
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
|
||||||
|
if (element.hasAttribute("order")) {
|
||||||
|
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
|
||||||
|
}
|
||||||
|
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
|
||||||
|
|
||||||
|
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
|
||||||
|
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
|
||||||
|
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
|
||||||
|
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
|
||||||
|
parserContext.registerComponent(compositeDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.transaction.config;
|
||||||
|
|
||||||
|
public abstract class TransactionManagementConfigUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bean name of the internally managed transaction advisor (used when mode == PROXY).
|
||||||
|
*/
|
||||||
|
public static final String TRANSACTION_ADVISOR_BEAN_NAME =
|
||||||
|
"org.springframework.transaction.config.internalTransactionAdvisor";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bean name of the internally managed transaction aspect (used when mode == ASPECTJ).
|
||||||
|
*/
|
||||||
|
public static final String TRANSACTION_ASPECT_BEAN_NAME =
|
||||||
|
"org.springframework.transaction.config.internalTransactionAspect";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class name of the AspectJ transaction management aspect.
|
||||||
|
*/
|
||||||
|
public static final String TRANSACTION_ASPECT_CLASS_NAME =
|
||||||
|
"org.springframework.transaction.aspectj.AnnotationTransactionAspect";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* 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.transaction.annotation;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.config.AdviceMode;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.CallCountingTransactionManager;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests.TransactionalTestBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests demonstrating use of @EnableTransactionManagement @Configuration classes.
|
||||||
|
*
|
||||||
|
* @author Chris Beams
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
public class EnableTransactionManagementTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void transactionProxyIsCreated() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(EnableTxConfig.class, TxManagerConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class);
|
||||||
|
assertThat("testBean is not a proxy", AopUtils.isAopProxy(bean), is(true));
|
||||||
|
Map<?,?> services = ctx.getBeansWithAnnotation(Service.class);
|
||||||
|
assertThat("Stereotype annotation not visible", services.containsKey("testBean"), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void txManagerIsResolvedOnInvocationOfTransactionalMethod() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(EnableTxConfig.class, TxManagerConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class);
|
||||||
|
|
||||||
|
// invoke a transactional method, causing the PlatformTransactionManager bean to be resolved.
|
||||||
|
bean.findAllFoos();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void txManagerIsResolvedCorrectlyWhenMultipleManagersArePresent() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
ctx.register(EnableTxConfig.class, MultiTxManagerConfig.class);
|
||||||
|
ctx.refresh();
|
||||||
|
TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class);
|
||||||
|
|
||||||
|
// invoke a transactional method, causing the PlatformTransactionManager bean to be resolved.
|
||||||
|
bean.findAllFoos();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cheap test just to prove that in ASPECTJ mode, the AnnotationTransactionAspect does indeed
|
||||||
|
* get loaded -- or in this case, attempted to be loaded at which point the test fails.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void proxyTypeAspectJCausesRegistrationOfAnnotationTransactionAspect() {
|
||||||
|
try {
|
||||||
|
new AnnotationConfigApplicationContext(EnableAspectJTxConfig.class, TxManagerConfig.class);
|
||||||
|
fail("should have thrown CNFE when trying to load AnnotationTransactionAspect. " +
|
||||||
|
"Do you actually have org.springframework.aspects on the classpath?");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
System.out.println(ex);
|
||||||
|
assertThat(ex.getMessage().endsWith("AspectJTransactionManagementConfiguration.class] cannot be opened because it does not exist"), is(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
static class EnableTxConfig {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
|
||||||
|
static class EnableAspectJTxConfig {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class TxManagerConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TransactionalTestBean testBean() {
|
||||||
|
return new TransactionalTestBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager txManager() {
|
||||||
|
return new CallCountingTransactionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class MultiTxManagerConfig extends TxManagerConfig implements TransactionManagementConfigurer {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager txManager2() {
|
||||||
|
return new CallCountingTransactionManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlatformTransactionManager createTransactionManager() {
|
||||||
|
return txManager2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue