跟着小马哥学系列之 Spring AOP(Spring 事务(源码分析)中)
学好路更宽,钱多少加班。 ——小马哥
简介
大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间《小马哥讲Spring AOP 编程思想》基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。
Spring事务(源码分析)上
Pointcut详解
Advice详解
Advisor详解
@EnableTransactionManagement 注解
- 启用 Spring 的注解驱动事务管理功能,类似于Spring的 tx:* XML 命名空间中的支持。在@Configuration类上使用如下
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public FooRepository fooRepository() {
// 配置并返回一个具有 @Transactional 方法的类
return new JdbcFooRepository(dataSource());
}
@Bean
public DataSource dataSource() {
// 配置并返回必要的JDBC数据源
}
@Bean
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(dataSource());
}
}
作为参考,上面的示例可以与下面的Spring XML配置进行比较:
<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>
- 在上述两个场景中,@EnableTransactionManagement 和 <tx:annotation-driven/> 负责注册必要的Spring 组件,这些组件支持注解驱动的事务管理,比如 TransactionInterceptor 和基于代理或AspectJ 的通知,当 JdbcFooRepository 的 @Transactional 方法被调用时,这些通知将拦截器编织到调用堆栈中。
- 两个示例之间的一个细微差别在于 PlatformTransactionManager bean 的命名:在 @Bean 的情况下,名称是 txManager(根据方法的名称);在XML 示例中,名称是 transactionManager。
- <tx:annotation-driven/> 在默认情况下硬安装名称为 transactionManager bean(通过名称查找) ,但是 @EnableTransactionManagement 更灵活;它将依靠容器,通过容器按类型查找 PlatformTransactionManager bean 。因此名称可以是 txManager、transactionManager 或 tm(这并不重要)。
- 对于那些希望在 @EnableTransactionManagement 和将要使用的确切事务管理器 bean 之间建立更直接的关系的人,可以实现 TransactionManagementConfigurer 回调接口——注意 implements 子句和下面的 @Override 注解方法:
@Configuration
@EnableTransactionManagement
public class AppConfig implements TransactionManagementConfigurer {
@Bean
public FooRepository fooRepository() {
// 配置并返回一个具有 @Transactional 方法的类
return new JdbcFooRepository(dataSource());
}
@Bean
public DataSource dataSource() {
// 配置并返回必要的JDBC数据源
}
@Bean
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(dataSource());
}
@Override
public TransactionManager annotationDrivenTransactionManager() {
return txManager();
}
}
- 这种方法可能是可取的,因为它更显式,或者为了区分出现在同一个容器中的两个 PlatformTransactionManager bean。顾名思义,annotationDrivenTransactionManager() 将用于处理 @Transactional 方法。
- mode() 属性控制如何应用通知:如果模式是 AdviceMode.PROXY(默认值),然后其他属性控制代理的行为。请注意,代理模式只允许拦截通过代理的调用;同一个类中的自调用(调用本类的其他方法)不能以这种方式被拦截。
- 注意,如果 mode() 被设置为 AdviceMode.ASPECTJ,那么 proxyTargetClass() 属性的值将被忽略。还请注意,在这种情况下,Spring 切面模块 JAR 必须出现在类路径中,通过编译时编织或加载时编织将切面应用于受影响的类。在这种情况下不涉及代理;本地调用也会被拦截。
元注解 | 描述 |
---|---|
@Target(ElementType.TYPE) | @EnableTransactionManagement 注解可以标注在 类、接口(包括注解类型)或枚举声明 |
@Retention(RetentionPolicy.RUNTIME) | @EnableTransactionManagement 注解将由编译器记录在类文件中,并在运行时由 VM 保留,因此可以以反射方式读取它们 |
@Import(TransactionManagermentConfigurationSelector.class) | 导入 TransactionManagermentConfigurationSelector 类 |
属性 | 描述 |
---|---|
proxyTargetClass() | 指示是否创建基于子类(CGLIB)的代理(true),而不是创建基于标准 Java 接口的代理(false)。默认为 false。仅当 mode() 设置为 AdviceMode.PROXY 时适用。请注意,将此属性设置为 true 将影响所有需要代理的 Spring 管理 bean,而不仅仅是那些标有 @Transactional 的 bean。 |
mode() | 说明应该如何应用事务性通知。默认为 AdviceMode.PROXY。请注意,代理模式只允许拦截通过代理的调用。同一类中的本地调用不能以这种方式被拦截;在本地调用中这样的方法上的事务性注解将被忽略,因为 Spring 的拦截器甚至不会在这样的运行时场景中起作用。对于更高级的拦截模式,考虑将其切换到AdviceMode.ASPECTJ。 |
order() | 指示当多个通知应用于特定连接点时事务 Advisor 程序的执行顺序(默认最低优先级) |
ImportSelector
- 接口,由类型实现,这些类型根据给定的选择标准(通常是一个或多个注解属性)确定应该导入哪个 @Configuration 类
- ImportSelector 可以实现以下任意一个 Aware 接口,并且它们各自的方法会在 selectImports 方法之前被调用
- EnvironmentAware
- BeanFactoryAware
- BeanClassLoaderAware
- ResourceLoaderAware
- 或者,类可以提供一个具有以下支持的一个或多个参数类型的构造函数
- Environment
- BeanFactory
- ClassLoader
- ResourceLoader
- ImportSelector 实现通常以与常规 @Import 注解相同的方式进行处理,但是,也可以推迟对导入的选择,直到所有 @Configuration 类都处理完毕(DeferredImportSelector )
方法 | 描述 |
---|---|
selectImports(AnnotationMetadata) | 根据导入的 @Configuration 类的 AnnotationMetadata 选择并返回应该导入的类的名称 |
AdviceModeImportSelector
ImportSelector 实现的便利基类,它基于注解(例如 @Enable* 注解)中的 AdviceMode 值选择导入
方法 | 描述 |
---|---|
selectImports(AnnotationMetadata) | 这个实现从泛型元数据中解析注解的类型,并验证注解实际上存在于导入的 @Configuration 类中,给定的注解具有 AdviceMode 类型的通知模式属性。然后调用 selectImports(AdviceMode) 方法,允许具体实现以安全和方便的方式选择导入 |
selectImports(AdviceMode) | 根据给定的 AdviceMode 确定应该导入哪些类。从这个方法返回 null 表示 AdviceMode 不能被处理或未知,应该抛出一个 IllegalArgumentException |
TransactionManagementConfigurationSelector
继承了 AdviceModeImportSelector 抽象类,实现了 selectImport(AdviceMode) 抽象方法。根据导入 @Configuration 类上的 EnableTransactionManagement.mode() 的值选择应该使用 AbstractTransactionManagementConfiguration 的哪个实现。
@Override
protected String[] selectImports(AdviceMode adviceMode) {
// EnableTransactionManagement.mode()的 PROXY 和 AspectJ 值分别返回
// ProxyTransactionManagementConfiguration 或 AspectJ(Jta)TransactionManagementConfiguration
switch (adviceMode) {
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);
}
AutoProxyRegistrar
根据当前 BeanDefinitionRegistry 注册一个自动代理创建器,基于 @Enable* 模式注解和 proxyTargetClass 设置为正确的值属性。实现了 ImportBeanDefinitionRegistrar 接口,主要是 registerBeanDefinitions 方法,注册 bean 定义
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 根据给定的注册表注册、升级并配置标准的自动代理创建器(APC)。通过在导入 @Configuration 类上查找最近注
// 解声明的 mode 和 proxyTargetClass 属性。如果mode 设置为 PROXY, APC 将被注册;如果 proxyTargetClass
// 设置为 true,那么 APC 将被迫使用子类(CGLIB)代理。
// 一些@Enable* 注解同时公开 mode 和 proxyTargetClass 属性。值得注意的是,这些功能中的大多数最终都是共
// 享一个 APC。由于这个原因,这个实现并不“关心”它找到了哪个注解——只要它公开了正确的 mode 和 proxyTargetClass 属性,
// APC 就可以同样地注册和配置。
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");
// 注解中是否包含 mode 和 proxyTargetClass 属性,并且属性值的类型也满足
// 即注册 InfrastructureAdvisorAutoProxyCreator 类型的 bean 定义
// 如果 proxyTargetClass 属性值是 true 并且注bean 定义注册中心包含一个
// org.springframework.aop.config.internalAutoProxyCreator bean 定义
// 则给这个bean 定义添加一个属性名为 proxyTargetClass,属性值为 true 的属性
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));
}
}
ImportAware
接口,由任何希望注入导入它的 @Configuration 类的 AnnotationMetadata 的 @Configuration 类实现。与使用 @Import 作为元注解的注解一起使用非常有用。
方法 | 描述 |
---|---|
setImportMetadata(AnnotationMetadata) | 设置导入 @Configuration 类的注解元数据 |
AbstractTransactionManagementConfiguration
抽象基于 @Configuration 类为启用 Spring 的注解驱动事务管理功能提供了公共结构
字段 | 描述 |
---|---|
AnnotationAttributes enableTx | EnableTransactionManagement 注解上的属性 |
TransactionManager txManager | 默认事务管理器,通过 TransactionManagementConfigurer 配置 |
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
// 获取 EnableTransactionManagement 注解元信息
this.enableTx = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
if (this.enableTx == null) {
throw new IllegalArgumentException(
"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
}
}
@Autowired(required = false)
void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
// 注入 TransactionManagementConfigurer 实例,不能超过 1 个
if (CollectionUtils.isEmpty(configurers)) {
return;
}
if (configurers.size() > 1) {
throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
}
TransactionManagementConfigurer configurer = configurers.iterator().next();
this.txManager = configurer.annotationDrivenTransactionManager();
}
// 定义 TransactionalEventListenerFactory Bean
@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
return new TransactionalEventListenerFactory();
}
ProxyTransactionManagementConfiguration
@Configuration 类,它注册启用基于代理的注解驱动的事务管理所需的 Spring 基础结构 bean。
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
// 把 Advice 和 TransactionAttributeSource 组装成 Advisor
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource,
TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
// 定义 TransactionAttributeSource Bean
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
// 定义 Advice Bean
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(
TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
TransactionAspectSupport
- 事务切面的基类,例如 TransactionInterceptor 或 AspectJ 切面。
- 这使得底层 Spring 事务基础设施可以轻松地用于为任何切面系统实现切面。子类负责以正确的顺序调用该类中的方法。
- 如果在 TransactionAttribute 中没有指定事务名称,则暴露的名称将是完全限定的类名 + “.” + 方法名(默认)。使用策略设计模式。
- PlatformTransactionManager 或 ReactiveTransactionManager 实现将执行实际的事务管理,而TransactionAttributeSource(例如,基于注解的)用于确定特定类或方法的事务定义。
- 如果一个事务切面的 PlatformTransactionManager 和 TransactionAttributeSource 是可序列化的,那么它就是可序列化的。
字段 | 描述 |
---|---|
Object DEFAULT_TRASACTION_MANAGER_KEY = new Object() | 用于存储默认事务管理器的键 |
ThreadLocal<TransactionInfo> transactionInfoHolder = new NamedThreadLocal<>(“Current aspect-driven transaction”) | 支持 currentTransactionStatus() 方法的持有者,如果切面涉及多个单一方法(如围绕通知的情况),则支持不同合作通知(例如,前和后通知)之间的通信 |
String transactionManagerBeanName | 事务管理 Bean 名称 |
TransactionManager | 事务管理实例 |
TransactionAttributeSource transactionAttributeSource | 事务属性源实例 |
BeanFactory beanFactory | 底层 IoC 容器 |
ConcurrentMap<Object, TransactionManager> transactionManagerCache | 事务管理缓存 |
方法 | 描述 |
---|---|
currentTransactionInfo() | 子类可以使用它返回当前的 TransactionInfo。只有不能在一个方法中处理所有操作的子类,比如涉及不同的前和后通知的 AspectJ 切面,才需要使用这种机制来获取当前的 TransactionInfo。像 AOP Alliance MethodInterceptor 这样的 around 通知可以在整个切面方法中保存对TransactionInfo 的引用。即使没有创建事务,也将返回 TransactionInfo。可以使用 TransactionInfo.hasTransaction() 方法进行查询。要了解具体的事务特征,请考虑使用 TransactionSynchronizationManager 的 isSynchronizationActive() 或 isActualTransactionActive() 方法 |
currentTransactionStatus() | 返回当前方法调用的事务状态。主要用于希望设置当前事务回滚但不抛出应用程序异常的代码 |
set/getTransactionManagerBeanName | 设置/获取事务管理 Bean 名称 |
set/getTransactionManager() | 设置/获取事务管理 |
setTransactionAttributes() | 重载方法,设置事务属性源 |
invokeWithinTransaction() 方法源码分析
基于 around-advice 的子类的常规委派,委派给这个类上的其他几个模板方法。能够处理 CallbackPreferringPlatformTransactionManager 以及常规的 PlatformTransactionManager 实现。
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
// 获取关联的 TransactionAttributeSource 对象。
TransactionAttributeSource tas = getTransactionAttributeSource();
// 通过关联的 TransactionAttributeSource 对象获取 TransactionAttribute
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 根据事务属性获取事务管理器
final TransactionManager tm = determineTransactionManager(txAttr);
// 这一块是对 Reactive 支持。现在使用的少,只分析长使用的传统的事务
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException(
"Unsupported annotated transaction on suspending function detected: " + method +
". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
}
// 把 TransactionManager 的 tm 转换成 PlatformTransactionManager 对象
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// 获取连接点标识符 类名 + "." + 方法名
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 如果事务属性没有设置或者事务管理器不是 CallbackPreferringPlatformTransactionManager 实例
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 通过 PlatformTransactionManager#getTransaction(txAttr) 获取 TransactionStatus 实例
// 封装 PlatformTransactionManager、TransactionAttribute、TransactionStatus、
// joinpointIdentification 在 TransactionInfo 实例你们,并绑定到当前线程
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 这是一个环绕通知:调用链中的下一个拦截器。这通常会导致调用目标对象。
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 目标调用异常,发生异常是否在事务属性关联的回滚异常中,如果在则通过管理的平台事务管理器回滚,否则提交事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 还原当前线程之前绑定的 TransactionInfo
cleanupTransactionInfo(txInfo);
}
// 如果存在 Vavr 库,进行处理
if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 没有发生异常,正常提交事务,通过 txInfo 管理的 PlatformTransactionManager 和 TransactionStatus
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
Object retVal = invocation.proceedWithInvocation();
if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
事务中的三大组件
Advice
TransactionInterceptor
AOP Alliance MethodInterceptor 用于声明性事务管理,用于 Spring 事务公共基础设施(PlatformTransactionManager/ ReactiveTransactionManager)。派生自 TransactionAspectSupport 类,该类包含与 Spring 的底层事务 API 的集成。TransactionInterceptor 简单地调用相关的超类方法,如 TransactionAspectSupport.invokeWithinTransaction(Method, Class, InvocationCallback)。TransactionInterceptor 是线程安全的。
/**
* 创建一个新的TransactionInterceptor。需要设置事务管理器和事务属性
*/
public TransactionInterceptor() {
}
/**
* 创建一个新的TransactionInterceptor。设置事务管理器和事务属性
*/
public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
setTransactionManager(ptm);
setTransactionAttributes(attributes);
}
/**
* 创建一个新的TransactionInterceptor。设置事务管理器和事务属性
*/
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// 确定目标类:可能是 null。应该向 TransactionAttributeSource 传递目标类和方法,方法可能来自接口。
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 委派给 TransactionAspectSupport 的 invokeWithinTransaction
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
}
Pointcut
TransactionAttributeSource
TransactionInterceptor 用于元数据检索的策略接口。实现知道如何从配置、源级别的元数据属性(如Java 5注解)或其他任何地方获取事务属性。
方法 | 描述 |
---|---|
isCandidateClass(Class<?>) | 确定给定的类是否是 TransactionAttributeSource 元数据格式的事务属性的候选类。如果该方法返回 false,则不会遍历给定类上的方法以获取 getTransactionAttribute(Method, Class<?>)。因此,返回 false 是对不受影响的类的优化,而 true 仅仅意味着需要对给定类上的每个方法进行完全的内省 |
getTransactionAttribute(Method, Class<?>) | 返回给定方法的事务属性,如果该方法是非事务性的,则返回 null |
AbstractFallbackTransactionAttributeSource
TransactionAttributeSource 的抽象实现,它缓存了方法的属性并实现了一个回退策略:
- 目标方法
- 目标类
- 声明方法
- 声明类/接口
默认情况下,如果与目标方法没有关联,则使用目标类的事务属性。与目标方法关联的任何事务属性都将完全覆盖类事务属性。如果在目标类中没有找到,将检查通过调用方法的接口(在使用JDK代理的情况下)。
这个实现在属性第一次被使用后通过方法缓存它们。如果希望允许动态更改事务属性(这是非常不可能的),那么可以将缓存设置为可配置的。缓存是可取的,因为评估回滚规则的成本很高。
方法 | 描述 |
---|---|
getCacheKey(Method, Class<?>) | 确定给定方法和目标类的缓存键。不能为重载的方法产生相同的键。必须为相同方法的不同实例产生相同的键 |
findTransactionAttribute(Class<?>) | 子类需要实现这个来返回给定类的事务属性(如果有的话) |
findTransactionAttribute(Method) | 子类需要实现这个来返回给定方法的事务属性(如果有的话) |
allowPublicMethodsOnly() | 应该只允许公共方法具有事务语义 默认实现返回 false |
主要分析 getTransactionAttribute 方法
通过调用此方法确定此事务属性。如果没有找到方法属性,则默认为类的事务属性。
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Object 方法则返回 null(在 Object 类上或者方法上你也标不上 Transactional 注解)
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 首先,看看是否有缓存值。
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value 将是指示没有事务属性的规范值,或者是实际的事务属性。
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// 如果缓存中没有,则要通过计算得到
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// 即使是没有属性值,也要缓存一个没有事务属性的 NULL_TRANSACTION_ATTRIBUTE 规范值
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
// 如果 targetClass 不是空,则是 targetClass 类类名 + '.' + 方法名,
// 否则是方法所在类类名 + '.' + 方法名
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
// 如果事务属性是 DefaultTransactionAttribute 实例,则设置 descriptor 属性
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
// 放入缓存
this.attributeCache.put(cacheKey, txAttr);
}
// 返回事务属性实例
return txAttr;
}
}
重中之重的 computeTransactionAttribute() 方法
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 不允许非公共方法。
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// 方法可能在接口上,但我们需要从目标类获取属性。如果目标类为空(既不是 Cglib 代理),则方法将保持不变。
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// 首先尝试事务属性是否在方法上(包括接口方法)。
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// 然后尝试事务属性是否在类上(包括接口)。
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
// 如果目标类方法和类上都没找到事务属性则从原方法、原方法所在的类上(cglib 代理类上)找
if (specificMethod != method) {
// 可退而求其次的方法是查看原始方法。
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// 最后回退到原始方法的类/接口。
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
// 都没找到返回 null
return null;
}
AnnotationTransactionAttributeSource
TransactionAttributeSource 接口的实现,用于处理 JDK 1.5+ 注解格式的事务元数据。这个类读取 Spring 的 JDK 1.5+ Transactional 注解,并向 Spring 的事务基础设施暴露相应的事务属性。还支持 JTA 1.2 的 Transactional 和 EJB3 的 TransactionAttribute 注解(如果有的话)。这个类也可以作为自定义 TransactionAttributeSource 的基类,或者通过 TransactionAnnotationParser 策略进行自定义。
AbstractFallbackTransactionAttributeSource 接口的 findTransactionAttribute()
重载方法,全都委派给 determineTransactionAttribute()
方法
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
// 构造 AnnotationTransactionAttriubteSource 时传入的,
// 或者是默认的 SpringTransactionAnnotationParser(Ejb3TransactionAnnotationParser、JtaTransactionAnnotationParser)
for (TransactionAnnotationParser parser : this.annotationParsers) {
// 使用解析器解析
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
TransactionAnnotationParser
用于解析已知事务注解类型的策略接口。AnnotationTransactionAttributeSource 委托这些解析器来支持特定的注解类型,比如 Spring 自己的 Transactional、JTA 1.2 的 Transactional 或 EJB3 的 TransactionAttribute。
方法 | 描述 |
---|---|
isCandidateClass(Class<?>) | 确定给定的类是否是 TransactionAnnotationParser 注解格式的事务属性的候选类。如果该方法返回 false,则不会遍历给定类上的方法以进行 parseTransactionAnnotation() 内省。因此,返回 false 是对不受影响的类的优化,而 true 仅仅意味着需要对给定类上的每个方法进行完全的内省 |
parseTransactionAnnotation(AnnotatedElement) | 基于该解析器所理解的注解类型,解析给定方法或类的事务属性。这实质上是将已知的事务注解解析到 Spring 的元数据属性类中。如果方法/类不是事务性的,则返回 null |
SpringTransactionAnnotationParser
解析 Spring 的 Transactional 注解的策略实现
@Override
public boolean isCandidateClass(Class<?> targetClass) {
// 首先判断传入的注解(Transactional.class)是否是 java 包下面的,如果是则返回 true
// 如果不是,则判断 targetClass 是否是 java 包下面的或者是 Ordered 类型,如果是则返回 false
// 其他情况都是 true
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
// 通过 AnnotatedElementUtils 工具类获取 AnnotatedElement 上的 Transactional 注解(包括父类)属性
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
// 如果有 Transactional 则,解析
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
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());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
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;
}
TransactionAttributeSourcePointcut
方法 | 描述 |
---|---|
getTransactionAttributeSource() | 获取底层 TransactionAttributeSource (可能为 null )。 由子类实现 |
在无参构造器里面默认设置 ClassFilte 为 TransactionAttributeSourceClassFilter 对象,在matches() 方法里面如果是 TransactionalProxy、 PlatformTransactionManager、PersistenceExceptionTranslator 实例,则返回 false。否则通过 getTransactionAttributeSource() 获取 TransactionAttributeSource 实例,通过 isCandidateClass 方法看是否匹配。方法匹配则是通过 getTransactionAttributeSource() 是否有 TransactionAttribute 实例。
Advisor
BeanFactoryTransactionAttributeSourceAdvisor
由 TransactionAttributeSource 驱动的 Advisor,用于包含事务性方法的事务通知 bean。不需要传入 Pointcut 实现,只需要设置 TransactionAttributeSource 即可。因为内部实现了 TransactionAttributeSourcePointcut 接口关联设置的 TransactionAttributeSource 实例 。
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};