SpringAOP[8]-如何自动代理@Transactional
事务的自动代理器为
InfrastructureAdvisorAutoProxyCreator
,若同时注册多个AbstractAutoProxyCreator
子类,可能会存在多处代理的情况。
多次代理的效果如下图所示:
为什么该类会被二次代理呢?
@Configuration @EnableTransactionManagement //注册了一个自动代理器 public class DefaultAdvisorAutoProxyCreatorConfig { //目标类 @Bean("tService") public TService tService() { return new TService(); } //注册了一个自动代理器 @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); //启用cglib代理 return defaultAdvisorAutoProxyCreator; } }
public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(DefaultAdvisorAutoProxyCreatorConfig.class); //可以使用@Primary指定元素,或直接使用name名获取。 TService bean = (TService) applicationContext.getBean("tService"); bean.say(); }
上述代码实际上注册了两个自动代理器
,而他们均是继承于org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
。
而AbstractAutoProxyCreator
类作用是为Bean生成代理对象,如何获取到bean
的Advisor
。它是交由了子类去实现。
AbstractAdvisorAutoProxyCreator
作为子类,实现了自动获取Advisor
的逻辑(实现了getAdvicesAndAdvisorsForBean
)。
1. 自动代理含义
1. 获取整个Spring容器Advisor类型的bean,由生成器
决定是否处理该Advisor。(若多个生成器均决定处理一个Advisor,可能存在二次代理)。
2. 每个生成器开始遍历自己决定处理的Advisor。通过Advisor的pointcut查看是否能切入bean。返回所有能够切入的Advisor。
3. 创建Proxy时,将能切入的Advisor传入,即完成自动代理。
解决上述二次代理的问题,即不要去注册defaultAdvisorAutoProxyCreator
。
2. 事务增强器织入bean
首先解析类/方法上的事务注解,若存在则解析为属性对象。那么如何判断注解是否存在?且如何解析为属性对象?
先抛开源码,看两个main函数(不依赖Spring容器)
2.1 解析自定义标签
自定义注解:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface MyTransaction { String value() default ""; }
public class TService { @MyTransaction("解析自定义注解") public void run1() { System.out.println("This is a run1() Method!"); } @Transactional public void say() { log.info("说话..."); } }
解析注解:
@Test public void test4() throws NoSuchMethodException { Method method = TService.class.getMethod("run1"); //读取事务注解 AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( method, MyTransaction.class, false, false); System.out.println(attributes); }
2.2 解析事务标签
得到的AnnotationAttributes
对象,如何转化为一个我们自定义的属性对象呢
?
public void test1() throws NoSuchMethodException { Method say = TService.class.getMethod("say"); //读取事务注解 AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( say, Transactional.class, false, false); //脱离Spring 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); System.out.println(JSON.toJSONString(rbta)); }
有小伙伴此时一定会好奇RollbackRuleAttribute
对象是干啥的。
@Test public void test3() { RollbackRuleAttribute rollbackRuleAttribute = new RollbackRuleAttribute(ArithmeticException.class); try { throw new BusinessException("业务异常"); } catch (Exception e) { //判断抛出的e(及其父类)是否是ArithmeticException异常 int depth = rollbackRuleAttribute.getDepth(e); System.out.println(depth); } }
也就是说,若异常(及其父类)符合指定的异常,返回正数;否则返回-1;
这样的话,就能决定是否是回滚的异常。
此时,注解标签解析为了属性对象。
2.3 Spring的事务切点
判断方法是否匹配时,会遍历bean中所有访问权限的方法。Spring会遍历public
方法,判断该method/class上是否存在Transactional
注解。若存在,解析为属性对象
,且通过匹配。
3. Spring解析事务注解
3.1 增强器的注册
首先需要存在一个Advisor
负责去增强@Transactional
标签的方法。
BeanFactoryTransactionAttributeSourceAdvisor
实现的是PointcutAdvisor
接口,既可以设置Advice,又可以设置Pointcut。但是下面代码中只配置了
Adice
,而pointcut
是由BeanFactoryTransactionAttributeSourceAdvisor
类完成的配置。@Configuration public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { //注册了Advisor @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) //声明的role为基础类(Spring内部使用的类) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); advisor.setTransactionAttributeSource(transactionAttributeSource()); //配置Advice advisor.setAdvice(transactionInterceptor()); if (this.enableTx != null) { advisor.setOrder(this.enableTx.<Integer>getNumber("order")); } return advisor; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } //注册了Advice @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor() { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource()); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } }
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { @Nullable private TransactionAttributeSource transactionAttributeSource; //pointcut 是TransactionAttributeSourcePointcut 的子类,实现了TransactionAttributeSource 方法。 //该方法的作用,是用户可以配置`解析器`。 private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override @Nullable protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } }; }
3.2 方法匹配
如何判断bean方法符合规则?判断是否能获取事务属性对象。
自动代理器会遍历bean的所有方法,判断是否与MethodMatcher
匹配。实际上会调用TransactionAttributeSourcePointcut
的matches
方法。
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { @Override public boolean matches(Method method, Class<?> targetClass) { TransactionAttributeSource tas = getTransactionAttributeSource(); //若TransactionAttributeSource 对象不为空,那么获取方法上的事务属性对象。 return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); } //抽象方法,但是注册的Advisor中的pointcut是TransactionAttributeSourcePointcut 子类。 //实际上获取的是TransactionAttributeSource 对象 @Nullable protected abstract TransactionAttributeSource getTransactionAttributeSource(); }
3.3 事务属性获取
解析事务注解,获取事务属性对象。
实际上TransactionAttributeSource
为3.1配置的AnnotationTransactionAttributeSource
对象。
当然这个类实现的只是特有的方法,而算法骨干由其父类AbstractFallbackTransactionAttributeSource
实现。
注意getTransactionAttribute
方法返回null,则证明pointcut不匹配bean的某方法。
public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource { @Override @Nullable public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { //若是Object的方法,直接返回null if (method.getDeclaringClass() == Object.class) { return null; } // 首先看缓存是否存在 Object cacheKey = getCacheKey(method, targetClass); TransactionAttribute cached = this.attributeCache.get(cacheKey); if (cached != null) { if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { return cached; } } else { //获取TransactionAttribute 对象的核心方法(如下所示) 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.isTraceEnabled()) { logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } this.attributeCache.put(cacheKey, txAttr); } return txAttr; } } @Nullable protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // 该方法是否要求必须是public级别(因为自动代理会对所有方法进行代匹配) if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } //获取明确类的方法(处理桥接方法) 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; } //获取原始方法上的事务配置 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; } }
下图的两个抽象方法,由子类实现。
还需要注意的一个细节,
AnnotationTransactionAttributeSource
是其唯一子类。public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource implements Serializable { public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) { this.publicMethodsOnly = publicMethodsOnly; if (jta12Present || ejb3Present) { this.annotationParsers = new LinkedHashSet<>(4); this.annotationParsers.add(new SpringTransactionAnnotationParser()); if (jta12Present) { this.annotationParsers.add(new JtaTransactionAnnotationParser()); } if (ejb3Present) { this.annotationParsers.add(new Ejb3TransactionAnnotationParser()); } } else { //通用模式下,为SpringTransactionAnnotationParser解析器 this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser()); } } @Override @Nullable protected TransactionAttribute findTransactionAttribute(Class<?> clazz) { return determineTransactionAttribute(clazz); } @Override @Nullable protected TransactionAttribute findTransactionAttribute(Method method) { return determineTransactionAttribute(method); } //遍历解析器,获取事务注解(方法如2.2所示) @Nullable protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { for (TransactionAnnotationParser parser : this.annotationParsers) { TransactionAttribute attr = parser.parseTransactionAnnotation(element); if (attr != null) { return attr; } } return null; } }
parseTransactionAnnotation()
方法如2.2所示,遍历方法/类上的事务注解。获取到TransactionAttribute
对象。
若
MethodMatcher
返回true,则证明该方法可以被事务增强器去增强。将Advisor加入到List中,并开始处理下一个Advisor。最终获取到所有可切入的Advisor。去创建代理对象。