第 3 步解析 @Transactional 注解通过 AnnotationTransactionAttributeSource#getTransactionAttribute(..) 方法完成的,我们一起来看看这个解析过程
@Transactional 注解的解析 1. getTransactionAttribute 方法 // AbstractFallbackTransactionAttributeSource.java @Override @Nullable public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // <1> java.lang.Object 内定义的方法跳过 if (method.getDeclaringClass() == Object.class) { return null; } // First, see if we have a cached value. // <2> 获取缓存 Key,MethodClassKey 对象,关联 Method 和 Class 对象 Object cacheKey = getCacheKey(method, targetClass); // <3> 尝试从缓存中获取该方法对应的 TransactionAttribute 对象 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. // <3.1> 缓存中缓存的是一个空的 TransactionAttribute 对象 // 表示没有相应的 @Transactional 注解,返回 `null` if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } // <3.2> 返回缓存的 TransactionAttribute 对象 else { return cached; } } // <4> 开始解析方法对应的 @Transactional 注解 else { // We need to work it out. // <4.1> 解析该方法或者类上面的 @Transactional 注解,封装成 RuleBasedTransactionAttribute 对象 // 优先从方法上面解析该注解,其次从类上解析该注解,没有的话返回的是 `null` TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); // Put it in the cache. // <4.2> 如果是 `null`,则缓存一个空的 TransactionAttribute 对象 if (txAttr == null) { this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } // <4.3> 否则,将该 TransactionAttribute 对象缓存 else { String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); if (txAttr instanceof DefaultTransactionAttribute) { // 设置方法的描述符(类名.方法名) ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification); } this.attributeCache.put(cacheKey, txAttr); } // <4.4> 返回这个 TransactionAttribute 对象 return txAttr; } }解析过程如下:
Object 内定义的方法跳过
获取缓存 Key,MethodClassKey 对象,关联 Method 和 Class 对象
尝试从缓存中获取该方法对应的 TransactionAttribute 对象,如果有的话
如果缓存中缓存的是一个“空”的 TransactionAttribute 对象,表示没有相应的 @Transactional 注解,返回 null
否则,返回缓存的 TransactionAttribute 对象
否则,开始解析方法对应的 @Transactional 注解
解析该方法或者类上面的 @Transactional 注解,封装成 RuleBasedTransactionAttribute 对象,优先从方法上面解析该注解,其次从类上解析该注解,没有的话返回的是 null
如果是 null,则缓存一个“空”的 TransactionAttribute 对象
否则,将该 TransactionAttribute 对象缓存
返回这个 TransactionAttribute 对象
注意,这里解析出来的 TransactionAttribute 会进行缓存,后续在 TransactionInterceptor(Advice)中无需解析,直接取缓存即可
上面第 4.1 步调用 computeTransactionAttribute(..) 方法解析 @Transactional 注解,如下:
2. computeTransactionAttribute 方法 // AbstractFallbackTransactionAttributeSource.java @Nullable protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // Don't allow no-public methods as required. // 如果不允许非 public 修饰的方法(默认允许),则判断是否为 public 修饰,不是的话返回 null 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); // First try is the method in the target class. // 通过 SpringTransactionAnnotationParser 解析方法上面的 @Transactional 注解 // 并将注解的元信息封装到 RuleBasedTransactionAttribute 中,没有注解的话返回 null TransactionAttribute txAttr = findTransactionAttribute(specificMethod); if (txAttr != null) { // 存在的话直接返回 return txAttr; } // Second try is the transaction attribute on the target class. // 如果方法上面没有,则尝试解析类上面的 @Transactional 注解 txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); // 存在这个注解,且方法是用户级别(不是 Spring 内部合成的) if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } // 如果还没有找到 @Transactional 注解的元信息,则尝试从原 Method 对象中查找 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; }