一、注解加载
1.1 流程
Spring是通过单例模式将@Transactional注解中的内容加载进来的,中间有一些是BeanFactory的工作,我省去了,直接从注解相关的类开始写流程了,流程大致如下图所示:
image.png
1.2 核心源码
源码部分主要记录一下spring容器怎么把注解加载进来的
1.2.1 getTransactionAttribute获取事务属性
// 判定方法的事务属性
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 先从缓存中尝试获取属性信息.
Object cacheKey = getCacheKey(method, targetClass);
Object cached = this.attributeCache.get(cacheKey);
if (cached != null) {
//如果缓存的是一个无事务对象
//直接返回空,这里使用==表示比较的对象引用是否相等.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return (TransactionAttribute) cached;
}
}
else {
// 当没有缓存是,需要重新计算获取事务属性.
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
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.isDebugEnabled()) {
logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
//将事务对象属性放到缓存中,缓存的key与类的类型和方法相关
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
1.2.2 computeTransactionAttribute计算事务属性
这个方法的主要功能是,根据方法和类的类型获取事务信息
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class> targetClass) {
//如果事务是只适用于public方法,且当前方法的修饰不是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 = AopUtils.getMostSpecificMethod(method, targetClass);
//调用findTransactionAttribute方法获取事务属性,但是这个方法比较简单,就不展开记录了,后面直接分解它调用的下一级方法
// First try is the method in the target class.
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (tx