声明式事务很⽅便,尤其纯注解模式,仅仅⼏个注解就能控制事务了 思考:这些注解都做了什么?好神奇!!!
@EnableTransactionManagement
@EnableTransactionManagement注解的定义如下:
/**
* Enables Spring's annotation-driven transaction management capability, similar to
* the support found in Spring's {@code <tx:*>} XML namespace. To be used on
* {@link org.springframework.context.annotation.Configuration @Configuration}
* classes to configure traditional, imperative transaction management or
* reactive transaction management.
*
* <p>The following example demonstrates imperative transaction management
* using a {@link org.springframework.transaction.PlatformTransactionManager
* PlatformTransactionManager}. For reactive transaction management, configure a
* {@link org.springframework.transaction.ReactiveTransactionManager
* ReactiveTransactionManager} instead.
*
* <pre class="code">
* @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());
* }
* }</pre>
*
* <p>For reference, the example above can be compared to the following Spring XML
* configuration:
*
* <pre class="code">
* <beans>
*
* <tx:annotation-driven/>
*
* <bean id="fooRepository" class="com.foo.JdbcFooRepository">
* <constructor-arg ref="dataSource"/>
* </bean>
*
* <bean id="dataSource" class="com.vendor.VendorDataSource"/>
*
* <bean id="transactionManager" class="org.sfwk...DataSourceTransactionManager">
* <constructor-arg ref="dataSource"/>
* </bean>
*
* </beans>
* </pre>
*
* In both of the scenarios above, {@code @EnableTransactionManagement} and {@code
* <tx:annotation-driven/>} 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 weaves the
* interceptor into the call stack when {@code JdbcFooRepository}'s {@code @Transactional}
* methods are invoked.
*
* <p>A minor difference between the two examples lies in the naming of the {@code
* TransactionManager} bean: In the {@code @Bean} case, the name is
* <em>"txManager"</em> (per the name of the method); in the XML case, the name is
* <em>"transactionManager"</em>. {@code <tx:annotation-driven/>} 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 TransactionManager} bean in the container. Thus the name
* can be "txManager", "transactionManager", or "tm": it simply does not matter.
*
* <p>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:
*
* <pre class="code">
* @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();
* }
* }</pre>
*
* <p>This approach may be desirable simply because it is more explicit, or it may be
* necessary in order to distinguish between two {@code TransactionManager} 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.
*
* <p>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. Please note that proxy mode allows for interception of calls through
* the proxy only; local calls within the same class cannot get intercepted that way.
*
* <p>Note that if the {@linkplain #mode} is set to {@link AdviceMode#ASPECTJ}, then the
* value of the {@link #proxyTargetClass} attribute will be ignored. Note also that in
* this case the {@code spring-aspects} module JAR must be present on the classpath, with
* compile-time weaving or load-time weaving applying the aspect to the affected classes.
* There is no proxy involved in such a scenario; local calls will be intercepted as well.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see TransactionManagementConfigurer
* @see TransactionManagementConfigurationSelector
* @see ProxyTransactionManagementConfiguration
* @see org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
@EnableTransactionManagement 注解使⽤ @Import 标签引⼊了TransactionManagementConfigurationSelector类,这个类⼜向容器中导⼊了两个重要的组件。
TransactionManagementConfigurationSelector类定义如下:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*
* 通过selectImports方法返回Spring需要扫描的全限定类名。Spring会注册这些类到Ioc容器中
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
//重点看Spring的
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
上述代码中为什么通过selectImports方法就可以把返回的全限定类名中的类注册进Spring Ioc容器?,因为TransactionManagementConfigurationSelector类继承了ImportSelector接口,ImportSelector接口中的selectImports就是可以将指定的类注册进Spring Ioc容器(这块可以尝试看看Spring源码)
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
/**
* The default advice mode attribute name.
*/
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;
}
/**
* 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}.
* <p>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}
*/
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
/**
* 用到了适配器设计模式,该方法为抽象方法,具体实现在子类TransactionManagementConfigurationSelector中
*/
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
}
回到上面的TransactionManagementConfigurationSelector类中,该类通过selectImports方法向Spring Ioc容器注册进了两个组件,分别是AutoProxyRegistrar和ProxyTransactionManagementConfiguration
加载事务控制组件
AutoProxyRegistrar
AutoProxyRegistrar类的定义如下:
/**
* 实现了ImportBeanDefinitionRegistrar接口,可以通过重写registerBeanDefinitions向Spring Ioc容器中注册BeanDifnition对象
*/
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
/**
* 可以通过重写registerBeanDefinitions向Spring Ioc容器中注册BeanDifnition对象
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
for (String annType : annTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
//重点这行代码
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(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 occurred 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));
}
}
}
通过上述代码可以看到,AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,可以通过重写registerBeanDefinitions方法向Spring Ioc容器中注册BeanDifnition对象。接着查看AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);这行代码。
接着:org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary方法如下:
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
//注册了InfrastructureAdvisorAutoProxyCreator类
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
发现最终,注册了⼀个叫做 InfrastructureAdvisorAutoProxyCreator 的 Bean,⽽这个类是 AbstractAutoProxyCreator的⼦类,实现了 SmartInstantiationAwareBeanPostProcessor 接⼝
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
继承体系结构图如下:
它实现了SmartInstantiationAwareBeanPostProcessor,说明这是⼀个后置处理器,⽽且跟 spring AOP 开启@EnableAspectJAutoProxy 时注册的 AnnotationAwareAspectJProxyCreator实 现的是同⼀个接⼝,所以说,声明式事务是 springAOP 思想的⼀种应⽤
ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration类定义如下:
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
//事务增强器
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
//向事务增强器中注⼊ 属性解析器 transactionAttributeSource
advisor.setTransactionAttributeSource(transactionAttributeSource);
// 向事务增强器中注⼊ 事务拦截器 transactionInterceptor
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// 属性解析器 transactionAttributeSource,用于解析@Transactional注解中的属性信息
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
//事务拦截器 transactionInterceptor
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
ProxyTransactionManagementConfiguration是⼀个容器配置类,注册了⼀个组件 transactionAdvisor,称为事务增强器,然后在这个事务增强器中⼜注⼊了两个属性: transactionAttributeSource,即属性解析器transactionAttributeSource 和 事务拦截器 transactionInterceptor
接着查看属性解析器 AnnotationTransactionAttributeSource ,源码如下:
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
implements Serializable {
private static final boolean jta12Present;
private static final boolean ejb3Present;
static {
ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
}
private final boolean publicMethodsOnly;
//注解解析器集合
private final Set<TransactionAnnotationParser> annotationParsers;
/**
* Create a default AnnotationTransactionAttributeSource, supporting
* public methods that carry the {@code Transactional} annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
*/
public AnnotationTransactionAttributeSource() {
this(true);
}
/**
* Create a custom AnnotationTransactionAttributeSource, supporting
* public methods that carry the {@code Transactional} annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
* @param publicMethodsOnly whether to support public methods that carry
* the {@code Transactional} annotation only (typically for use
* with proxy-based AOP), or protected/private methods as well
* (typically used with AspectJ class weaving)
*/
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
if (jta12Present || ejb3Present) {
this.annotationParsers = new LinkedHashSet<>(4);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
else {
this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
}
}
}
属性解析器有⼀个成员变量是annotationParsers,是⼀个集合,可以添加多种注解解析器 (TransactionAnnotationParser),我们关注 Spring 的注解解析器,部分源码如下
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
@Override
public boolean isCandidateClass(Class<?> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
}
/**
* 解析@Transactional中的属性信息,比如propagation事务传播行为,isolation事务隔离级别等等
*/
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
String timeoutString = attributes.getString("timeoutString");
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
"Specify 'timeout' or 'timeoutString', not both");
rbta.setTimeoutString(timeoutString);
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
@Override
public boolean equals(@Nullable Object other) {
return (other instanceof SpringTransactionAnnotationParser);
}
@Override
public int hashCode() {
return SpringTransactionAnnotationParser.class.hashCode();
}
}
属性解析器的作⽤之⼀就是⽤来解析@Transaction注解
TransactionInterceptor 事务拦截器,部分源码如下
/**
* 实现了MethodInterceptor接口,重点看重写的invoke方法
*/
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
/**
* Create a new TransactionInterceptor.
* <p>Transaction manager and transaction attributes still need to be set.
* @see #setTransactionManager
* @see #setTransactionAttributes(java.util.Properties)
* @see #setTransactionAttributeSource(TransactionAttributeSource)
*/
public TransactionInterceptor() {
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param tas the attribute source to be used to find transaction attributes
* @since 5.2.5
* @see #setTransactionManager
* @see #setTransactionAttributeSource
*/
public TransactionInterceptor(TransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param tas the attribute source to be used to find transaction attributes
* @see #setTransactionManager
* @see #setTransactionAttributeSource
* @deprecated as of 5.2.5, in favor of
* {@link #TransactionInterceptor(TransactionManager, TransactionAttributeSource)}
*/
@Deprecated
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param attributes the transaction attributes in properties format
* @see #setTransactionManager
* @see #setTransactionAttributes(java.util.Properties)
* @deprecated as of 5.2.5, in favor of {@link #setTransactionAttributes(Properties)}
*/
@Deprecated
public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
setTransactionManager(ptm);
setTransactionAttributes(attributes);
}
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
//重点看invokeWithinTransaction方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void writeObject(ObjectOutputStream oos) throws IOException {
// Rely on default serialization, although this class itself doesn't carry state anyway...
oos.defaultWriteObject();
// Deserialize superclass fields.
oos.writeObject(getTransactionManagerBeanName());
oos.writeObject(getTransactionManager());
oos.writeObject(getTransactionAttributeSource());
oos.writeObject(getBeanFactory());
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization, although this class itself doesn't carry state anyway...
ois.defaultReadObject();
// Serialize all relevant superclass fields.
// Superclass can't implement Serializable because it also serves as base class
// for AspectJ aspects (which are not allowed to implement Serializable)!
setTransactionManagerBeanName((String) ois.readObject());
setTransactionManager((PlatformTransactionManager) ois.readObject());
setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
setBeanFactory((BeanFactory) ois.readObject());
}
}
接着查看invoke方法中的invokeWithinTransaction方法,org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction如下: