文章目录
前言
这篇文章来讲讲Spring的重要组成部分@Transactional注解是如何生效的
一、@Transactional的作用
写java的都知道,这个注解是用来给方法添加事务的,一般情况我们都是用在访问数据库的service的逻辑上。
二、@Transactional如何生效的
1.@EnableTransactionManagement
项目要使用@Transactional来管理事务,就必须要在Application类上添加@EnableTransactionManagement注解,来解析下该注解吧
@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 2147483647;
}
太眼熟了啊喂,也有Import注解,那废话不多说,咱们来看看Import进来的类是个什么作用。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
public TransactionManagementConfigurationSelector() {
}
protected String[] selectImports(AdviceMode adviceMode) {
switch(adviceMode) {
// 默认情况下,adviceMode是PROXY,可以查看上面的注解源码
case PROXY:
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[]{this.determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";
}
}
至于selectImport的实现逻辑,可以参看我那篇讲解@EnableAutoConfiguration注解实现原理的文章。
简而言之:此处spring会把AutoProxyRegistrar和ProxyTransactionManagementConfiguration添加进容器,同时当成配置类解析一下。
2. AutoProxyRegistrar
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
/**
* 这个类会在configurationClassPostProcessor的postProcessBeanDefinitionRegistry
* 里面统一调用ImportBeanDefinitionRegistrar的registerBeanDefinitions时被调用
* 然后注册相应的BeanDefinition
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 获取@EnableTransactionManagement所在配置类(XXXApplication)上的注解元信息
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
// 遍历注解
for (String annType : annTypes) {
// 遍历XXXApplication上所有的注解类型,分别封装成candidate,
// 可以理解为将注解中的属性转换成一个map
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
// 直接从map中获取属性
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
// mode,代理模型,一般都是SpringAOP
// proxyTargetClass,是否使用cglib代理,默认是false
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&Boolean.class == proxyTargetClass.getClass()) {
// 注解中存在这两个属性,并且属性类型符合要求,表示找到了合适的注解
candidateFound = true;
// 实际上会往容器中注册一个InfrastructureAdvisorAutoProxyCreator
// 至于InfrastructureAdvisorAutoProxyCreator的作用,后面再说
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
// 默认情况下,此处逻辑不会走
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
}
3 ProxyTransactionManagementConfiguration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
public ProxyTransactionManagementConfiguration() {
}
// 注册了一个BeanFactoryTransactionAttributeSourceAdvisor
// advisor就是一个绑定了切点的通知
// 可以看到通知就是TransactionInterceptor
// 在BeanFactoryTransactionAttributeSourceAdvisor中要创建pointCut
// 切点会通过TransactionAttributeSource去解析@Transacational注解
// 只会对有这个注解的方法进行拦截
// AOP advisor 重要的两个东西 pointCut和 Advice 就都有了
@Bean(
name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
)
@Role(2)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
// 事务aop的通知advisor
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder((Integer)this.enableTx.getNumber("order"));
}
return advisor;
}
// 注册一个AnnotationTransactionAttributeSource
// 这个类的主要作用是用来解析@Transacational注解
@Bean
@Role(2)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
// 事务是通过AOP实现的,AOP的核心就是拦截器
// 这里就是注册了实现事务需要的拦截器
@Bean
@Role(2)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
3.1 advisor中的pointCut
在BeanFactoryTransactionAttributeSourceAdvisor中有个pointCut,这个pointCut的类型是TransactionAttributeSourcePointcut,在这个类里面有个matches方法是用来判断target类的方法在执行时是否需要使用该advisor的advice的。
@Override
public boolean matches(Method method, Class<?> targetClass) {
if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
//因为我们往advisor里传递了TransactionAttributeSource,所以tas不为空
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
所以我们重点来看一下getTransactionAttribute方法
/**
* // 获取事务对应的属性,实际上返回一个AnnotationTransactionAttributeSource
* // 之后再调用AnnotationTransactionAttributeSource的getTransactionAttribute
* // getTransactionAttribute:先从拦截的方法上找@Transactional注解
* // 如果方法上没有的话,再从方法所在的类上找,如果类上还没有的话尝试从接口或者父类上找
*/
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
// 从缓存里找
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// We need to work it out.
// 此处是真正的解析
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
// 解析的结果缓存起来,如果为事务属性为null,也放入一个标志
// 代表这个方法不需要进行事务管理
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
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;
}
}
再来看看真正判断方法是否要启用advisor的逻辑
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
// 默认情况下allowPublicMethodsOnly为true
// 这意味着@Transactional如果放在非public方法上不会生效
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
// method是接口中的方法
// specificMethod是具体实现类的方法
// 相当于根据接口获取到实现类的代理类的对应方法
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
// 首先从方法上找@Transactional注解
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
// 其次从方法的类(目标类)上找@Transactional注解
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
//到接口和接口中的方法上找注解
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
由此可见,在方法或者targetClass上加@Transactional都可以,甚至在接口或者接口的方法上加@Transactional也可以。
总结
小结
- 通过对@EnableTransactionManagement的解析,来探寻@Transactional是如何基于AOP原理生效的。
主要是生成了一个BeanFactoryTransactionAttributeSourceAdvisor。
AOP
- 针对AOP中重要的pointCut。pointCut定义Advisor是否可以针对targetClass的方法使用时进行启用,在BeanFactoryTransactionAttributeSourceAdvisor中定义了TransactionAttributeSourcePointcut类型的pointCut,该pointCut中的matches方法说明了,只要targetClass的method上加了@Transactional或者targetClass上加了@Transactional,甚至接口类和方法上加了@Transactional,都可以在method执行时,匹配上该advisor
- 针对AOP中重要的Advice,用TransactionInterceptor来实现的,至于具体的执行逻辑,其实就是其内部的invoke方法,具体执行的是invokeWithinTransaction,这个值得专门写一篇文章来讲
okay,that’s all
下一篇主要讲TransactionInterceptor的运行逻辑,点击这里查看