diff --git a/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AspectJTransactionManagementConfiguration.java b/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AspectJTransactionManagementConfiguration.java index 1d250394c68..54c30a1af0a 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AspectJTransactionManagementConfiguration.java +++ b/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AspectJTransactionManagementConfiguration.java @@ -21,8 +21,19 @@ 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.annotation.EnableTransactionManagement; +import org.springframework.transaction.annotation.TransactionManagementConfigurationSelector; import org.springframework.transaction.config.TransactionManagementConfigUtils; +/** + * {@code @Configuration} class that registers the Spring infrastructure beans necessary + * to enable AspectJ-based annotation-driven transaction management. + * + * @author Chris Beams + * @since 3.1 + * @see EnableTransactionManagement + * @see TransactionManagementConfigurationSelector + */ @Configuration public class AspectJTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java index 1c7676af56f..64020e79f72 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AbstractTransactionManagementConfiguration.java @@ -27,8 +27,8 @@ 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. + * Abstract base {@code @Configuration} class providing common structure for enabling + * Spring's annotation-driven transaction management capability. * * @author Chris Beams * @since 3.1 diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/EnableTransactionManagement.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/EnableTransactionManagement.java index b425e44d175..922a0566db3 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/EnableTransactionManagement.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/EnableTransactionManagement.java @@ -26,6 +26,114 @@ import org.springframework.context.annotation.Import; import org.springframework.context.config.AdviceMode; import org.springframework.core.Ordered; +/** + * Enables Spring's annotation-driven transaction management capability, similar to + * the support found in Spring's {@code } XML namespace. To be used + * on @{@link org.springframework.context.annotation.Configuration Configuration} classes + * as follows: + *
+ * @Configuration
+ * @EnableTransactionManagement
+ * public class AppConfig {
+ *     @Bean
+ *     public FooRepository fooRepository() {
+ *         // configure and return a class having @Transactional methods
+ *         return new JdbcFooRepository(dataSource());
+ *     }
+ *
+ *     @Bean
+ *     public DataSource dataSource() {
+ *         // configure and return the necessary JDBC DataSource
+ *     }
+ *
+ *     @Bean
+ *     public PlatformTransactionManager txManager() {
+ *         return new DataSourceTransactionManager(dataSource());
+ *     }
+ * }
+ * + *

For reference, the example above can be compared to the following Spring XML + * configuration: + *

+ * {@code
+ * 
+ *     
+ *     
+ *         
+ *     
+ *     
+ *     
+ *         
+ *     
+ * 
+ * }
+ * In both of the scenarios above, {@code @EnableTransactionManagement} and {@code + * } are responsible for registering the necessary Spring + * components that power annotation-driven transaction management, such as the + * TransactionInterceptor and the proxy- or AspectJ-based advice that weave the + * interceptor into the call stack when {@code JdbcFooRepository}'s {@code @Transacational} + * methods are invoked. + * + *

A minor difference between the two examples lies in the naming of the {@code + * PlatformTransactionManager} bean: In the {@code @Bean} case, the name is + * "txManager" (per the name of the method); in the XML case, the name is + * "transactionManager". The {@code } is hard-wired to + * look for a bean named "transactionManager" by default, however + * {@code @EnableTransactionManagement} is more flexible; it will fall back to a by-type + * lookup for any {@code PlatformTransactionManager} bean in the container. Thus the name + * can be "txManager", "transactionManager", or "tm": it simply does not matter. + * + *

For those that wish to establish a more direct relationship between + * {@code @EnableTransactionManagement} and the exact transaction manager bean to be used, + * the {@link TransactionManagementConfigurer} callback interface may be implemented - + * notice the {@code implements} clause and the {@code @Override}-annotated method below: + *

+ * @Configuration
+ * @EnableTransactionManagement
+ * public class AppConfig implements TransactionManagementConfigurer {
+ *     @Bean
+ *     public FooRepository fooRepository() {
+ *         // configure and return a class having @Transactional methods
+ *         return new JdbcFooRepository(dataSource());
+ *     }
+ *
+ *     @Bean
+ *     public DataSource dataSource() {
+ *         // configure and return the necessary JDBC DataSource
+ *     }
+ *
+ *     @Bean
+ *     public PlatformTransactionManager txManager() {
+ *         return new DataSourceTransactionManager(dataSource());
+ *     }
+ *
+ *     @Override
+ *     public PlatformTransactionManager annotationDrivenTransactionManager() {
+ *         return txManager();
+ *     }
+ * }
+ * This approach may be desirable simply because it is more explicit, or it may be + * necessary in order to distinguish between two {@code PlatformTransactionManager} beans + * present in the same container. As the name suggests, the + * {@code annotationDrivenTransactionManager()} will be the one used for processing + * {@code @Transactional} methods. See {@link TransactionManagementConfigurer} Javadoc + * for further details. + * + *

The {@link #mode()} attribute controls how advice is applied; if the mode is + * {@link AdviceMode#PROXY} (the default), then the other attributes control the behavior + * of the proxying. + * + *

Note that if the {@linkplain #mode} is set to {@link AdviceMode#ASPECTJ}, then + * the {@link #proxyTargetClass()} attribute is obsolete. Note also that in this case the + * {@code spring-aspects} module JAR must be present on the classpath.

+ * + * @author Chris Beams + * @since 3.1 + * @see TransactionManagementConfigurer + * @see TransactionManagementConfigurationSelector + * @see ProxyTransactionManagementConfiguration + * @see org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration + */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @@ -33,11 +141,12 @@ import org.springframework.core.Ordered; 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}. + * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed + * to standard Java interface-based proxies. The default is {@code false}. + * Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}. * - *

Note: Class-based proxies require the {@link Transactional @Transactional} - * annotation to be defined on the concrete class. Annotations in interfaces will + *

Note that subclass-based proxies require the {@link Transactional @Transactional} + * 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; @@ -52,7 +161,7 @@ public @interface EnableTransactionManagement { /** * Indicate the ordering of the execution of the transaction advisor * when multiple advices are applied at a specific joinpoint. - * The default is lowest priority. + * The default is {@link Ordered#LOWEST_PRECEDENCE}. */ int order() default Ordered.LOWEST_PRECEDENCE; } diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.java index a28acf77999..2dca350475b 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.java @@ -27,6 +27,15 @@ import org.springframework.transaction.interceptor.BeanFactoryTransactionAttribu import org.springframework.transaction.interceptor.TransactionAttributeSource; import org.springframework.transaction.interceptor.TransactionInterceptor; +/** + * {@code @Configuration} class that registers the Spring infrastructure beans necessary + * to enable proxy-based annotation-driven transaction management. + * + * @author Chris Beams + * @since 3.1 + * @see EnableTransactionManagement + * @see TransactionManagementConfigurationSelector + */ @Configuration public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { 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 0fb0ddfc3e0..69ce2b0b5fd 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 @@ -23,8 +23,26 @@ import org.springframework.context.config.AdviceMode; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.Assert; +/** + * Selects which implementation of {@link AbstractTransactionManagementConfiguration} + * should be used based on the value of {@link EnableTransactionManagement#mode} on the + * importing @{@link Configuration} class. + * + * @author Chris Beams + * @since 3.1 + * @see EnableTransactionManagement + * @see AbstractTransactionManagementConfiguration + * @see ProxyTransactionManagementConfiguration + * @see org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration + */ public class TransactionManagementConfigurationSelector implements ImportSelector { + /** + * Import {@link ProxyTransactionManagementConfiguration} if {@link + * EnableTransactionManagement#mode()} equals {@code PROXY}, otherwise import {@link + * org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration + * AspectJTransactionManagementConfiguration}. + */ public String[] selectImports(AnnotationMetadata importingClassMetadata) { Map enableTx = importingClassMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName()); diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurer.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurer.java index 7effb75a295..fd95d50886b 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurer.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurer.java @@ -18,8 +18,66 @@ package org.springframework.transaction.annotation; import org.springframework.transaction.PlatformTransactionManager; +/** + * Interface to be implemented by @{@link org.springframework.context.annotation.Configuration + * Configuration} classes annotated with @{@link EnableTransactionManagement} that wish + * or need to specify explicitly the {@link PlatformTransactionManager} bean to be used + * for annotation-driven transaction management, as opposed to the default approach of a + * by-type lookup. One reason this might be necessary is if there are two + * {@code PlatformTransactionManager} implementations present in the container. + * + *

See @{@link EnableTransactionManagement} for general examples and context; see + * {@link #annotationDrivenTransactionManager()} below for detailed instructions. + * + *

Note that in by-type lookup disambiguation cases, an alternative approach to + * implementing this interface is to simply mark one of the offending {@code + * PlatformTransactionManager} {@code @Bean} methods as @{@link + * org.springframework.context.annotation.Primary Primary}. + * + * @author Chris Beams + * @since 3.1 + * @see EnableTransactionManagement + * @see org.springframework.context.annotation.Primary + */ public interface TransactionManagementConfigurer { + /** + * Return the transaction manager bean to use for annotation-driven database + * transaction management, i.e. when processing {@code @Transactional} methods. + * + *

There are two basic approaches to implementing this method: + *

1. Implement the method and annotate it with {@code @Bean}

+ * In this case, the implementing {@code @Configuration} class implements this method, + * marks it with {@code @Bean} and configures and returns the transaction manager + * directly within the method body: + *
+	 * @Bean
+	 * @Override
+	 * public PlatformTransactionManager createTransactionManager() {
+	 *     return new DataSourceTransactionManager(dataSource());
+	 * }
+ *

2. Implement the method without {@code @Bean} and delegate to another existing + * {@code @Bean} method

+ *
+	 * @Bean
+	 * public PlatformTransactionManager txManager() {
+	 *     return new DataSourceTransactionManager(dataSource());
+	 * }
+	 *
+	 * @Override
+	 * public PlatformTransactionManager createTransactionManager() {
+	 *     return txManager(); // reference the existing {@code @Bean} method above
+	 * }
+ * + * If taking approach #2, be sure that only one of the methods is marked with + * {@code @Bean}! + * + *

In either scenario #1 or #2, it is important that the + * {@code PlatformTransactionManager} instance is managed as a Spring bean within the + * container as all {@code PlatformTransactionManager} implementations take + * advantage of Spring lifecycle callbacks such as {@code InitializingBean} and {@code + * BeanFactoryAware}. + */ PlatformTransactionManager annotationDrivenTransactionManager(); } diff --git a/org.springframework.transaction/src/main/resources/org/springframework/transaction/config/spring-tx-3.1.xsd b/org.springframework.transaction/src/main/resources/org/springframework/transaction/config/spring-tx-3.1.xsd index 8d76ee3a43b..0ae5641438f 100644 --- a/org.springframework.transaction/src/main/resources/org/springframework/transaction/config/spring-tx-3.1.xsd +++ b/org.springframework.transaction/src/main/resources/org/springframework/transaction/config/spring-tx-3.1.xsd @@ -76,6 +76,9 @@ Transaction semantics such as propagation settings, the isolation level, the rollback rules, etc are all defined in the annotation metadata. + + See org.springframework.transaction.annotation.EnableTransactionManagement Javadoc + for information on code-based alternatives to this XML element. ]]>