跟着小马哥学系列之 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 enableTxEnableTransactionManagement 注解上的属性
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 的抽象实现,它缓存了方法的属性并实现了一个回退策略:

    1. 目标方法
    2. 目标类
    3. 声明方法
    4. 声明类/接口
  • 默认情况下,如果与目标方法没有关联,则使用目标类的事务属性。与目标方法关联的任何事务属性都将完全覆盖类事务属性。如果在目标类中没有找到,将检查通过调用方法的接口(在使用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;
		}
	};
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿大叔文海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值