在Spring事务用法示例与实现原理中咱们讲到,在进行tx:annotation-driven
标签解析的时候,Spring注册了三个bean:BeanFactoryTransactionAttributeSourceAdvisor,TransactionInterceptor和AnnotationTransactionAttributeSource。这里BeanFactoryTransactionAttributeSourceAdvisor本质上是一个Advisor,在Spring Aop中,Advisor封装了切面环绕的全部信息,最主要的就是Advice和Pointcut。这里Advice中包含了须要环绕的切面逻辑,而Pointcut中则封装了进行方法过滤的判断条件,即用于判断某个方法是否须要环绕当前切面逻辑的条件。关于这三个类的关系以下:java
对应的,Spring事务中声明的这三个bean就与切面环绕所使用的组织结构彻底一致,这里TransactionInterceptor实现了Advice接口,进行事务切面环绕的逻辑也封装在了这个bean中;AnnotationTransactionAttributeSource则封装了目标方法是否须要进行事务逻辑环绕的判断逻辑,实际上,其没有实现Pointcut接口,可是BeanFactoryTransactionAttributeSourceAdvisor在进行目标方法判断的时候实际上仍是委托给了AnnotationTransactionAttributeSource进行。对于这几个类的讲解咱们会依次进行,本文则主要讲解AnnotationTransactionAttributeSource是如何判断目标方法是否须要进行事务逻辑环绕的。缓存
在BeanFactoryTransactionAttributeSourceAdvisor中,其声明了一个TransactionAttributeSourcePointcut类型的属性,而且实现了其getTransactionAttributeSource()
方法,这个方法的返回值是一个TransactionAttributeSource类型的对象,而实际上,其返回的就是AnnotationTransactionAttributeSource。这里建立Pointcut的源码以下:ide
@Nullable private TransactionAttributeSource transactionAttributeSource; private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { // 将标签解析时注册的AnnotationTransactionAttributeSource返回 protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } };
须要强调的是,这里返回的AnnotationTransactionAttributeSource就是在tx:annotation-driven
标签解析时注册的bean。既然BeanFactoryTransactionAttributeSourceAdvisor在其内部声明了一个Pointcut对象,那么对于目标方法的匹配应该在Pointcut.matches()
方法中,也就是说Spring事务是否须要环绕切面逻辑的判断就在TransactionAttributeSourcePointcut.matches()
中,以下是该方法的源码:this
@Override public boolean matches(Method method, @Nullable Class<?> targetClass) { // 若是目标类不为空,而且是已经使用Transaction环绕后生成的类,则会将其过滤掉 if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) { return false; } // 获取TransactionAttributeSource对象,这个方法也就是上面一个代码片断中实现的方法, // 也就是说这个方法将返回AnnotationTransactionAttributeSource TransactionAttributeSource tas = getTransactionAttributeSource(); // 经过TransactionAttributeSource获取事务属性配置,若是当前方法没有配置事务,则不对其进行环绕 return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
能够看到,matches()
方法实现比较简单,其首先会判断目标类是不是已经环绕过事务逻辑所生成的类。这里的TransactionalProxy继承自SpringProxy,而且内部没有任何方法,其仅仅只是起到一个标记做用,只要是使用事务代理生成的类都会实现这个接口;而后会经过getTransactionAttributeSource()
方法获取TransactionAttributeSource对象;最后经过TransactionAttributeSource.getTransactionAttribute()
方法获取目标方法上的事务配置,若是没有则不对当前方法进行环绕。.net
这里Spring事务判断某个方法是否须要环绕的逻辑总体上是很是简单的,就是判断目标方法是否配置了事务相关的属性,好比使用@Transactional
注解的时候就是判断目标方法上是否有该注解,而且解析该注解相关的属性。debug
对于事务属性的解析,其主要在TransactionAttributeSource.getTransactionAttribute()
方法中,这里TransactionAttributeSource只是一个接口,对于不一样类型的事务声明,其有不一样的实现子类,好比咱们这里使用的AnnotationTransactionAttributeSource就主要用于解析使用注解声明的事务,以下是其getTransactionAttribute()方法的源码:代理
@Override @Nullable public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // 若是当前方法是Object类中的方法,则直接返回 if (method.getDeclaringClass() == Object.class) { return null; } // 获取当前方法缓存使用的key 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); // 若是生成的事务属性是DefaultTransactionAttribute类型的, // 则将方法签名设置到其descriptor属性中 if (txAttr instanceof DefaultTransactionAttribute) { ((DefaultTransactionAttribute) txAttr) .setDescriptor(methodIdentification); } if (logger.isDebugEnabled()) { logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } // 缓存当前方法的解析结果 this.attributeCache.put(cacheKey, txAttr); } return txAttr; } }
这里getTransactionAttribute()
方法是解析事务属性的主干逻辑,其首先从缓存中获取当前方法解析获得的事务属性,若是没有解析过则进行解析,而且缓存解析结果。能够看到,解析事务属性的实际逻辑在computeTransactionAttribute()
方法中,以下是该方法的源码:code
@Nullable protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // 若是设置了只对public方法进行事务代理,而且当前方法不是public的,则返回null if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } Class<?> userClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : null); // 获取最为准确的方法,即若是传入的method只是一个接口方法,则会去找其实现类的同一方法进行解析 Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass); // 若是当前方法是一个泛型方法,则会找Class文件中实际实现的方法 specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); // 解析目标方法,获取其是否存在事务属性,若是存在则直接返回 TransactionAttribute txAttr = findTransactionAttribute(specificMethod); if (txAttr != null) { return txAttr; } // 解析目标方法所在的类,判断其是否标注有事务属性,若是存在,而且目标方法是用户实现的方法,则直接返回 txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } // 若是经过解析到的方法没法找到事务属性,则判断解析获得的方法与传入的目标方法是否为同一个方法, // 若是不是同一个方法,则尝试对传入的方法及其所在的类进行事务属性解析 if (specificMethod != method) { // 对传入方法解析事务属性,若是存在,则直接返回 txAttr = findTransactionAttribute(method); if (txAttr != null) { return txAttr; } // 对传入方法所在类进行事务属性解析,若是存在,则直接返回 txAttr = findTransactionAttribute(method.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } } return null; }
这里对事务属性的解析主要分为两部分:对目标方法进行解析和对传入方法进行解析。这两部分的解析都分别进行了方法上的事务属性解析和方法所在类的事务属性解析。能够看到,将事务属性转换为TransactionAttribute对象的逻辑主要在findTransactionAttribute()
方法中,以下是该方法的实现逻辑(中间略去部分简单调用):对象
@Nullable protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) { for (TransactionAnnotationParser annotationParser : this.annotationParsers) { TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae); if (attr != null) { return attr; } } return null; }
determineTransactionAttribute()
方法逻辑比较简单,最终对事务属性进行转换的逻辑是在TransactionAnnotationParser中的,这里Spring事务使用的则是SpringTransactionAnnotationParser,以下是其parseTransactionAnnotation()方法的源码:blog
@Override @Nullable public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) { // 判断目标方法上是否存在@Transactional注解,若是不存在,则直接返回 AnnotationAttributes attributes = AnnotatedElementUtils .findMergedAnnotationAttributes(ae, Transactional.class, false, false); if (attributes != null) { // 若是目标方法上存在@Transactional注解,则获取注解值,而且封装为TransactionAttribute返回 return parseTransactionAnnotation(attributes); } else { return null; } } protected TransactionAttribute parseTransactionAnnotation( AnnotationAttributes attributes) { RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); // 获取注解上的propagation值 Propagation propagation = attributes.getEnum("propagation"); rbta.setPropagationBehavior(propagation.value()); // 获取注解上的isolation属性值 Isolation isolation = attributes.getEnum("isolation"); rbta.setIsolationLevel(isolation.value()); // 获取注解上的timeout属性值 rbta.setTimeout(attributes.getNumber("timeout").intValue()); // 获取注解上的readOnly属性值 rbta.setReadOnly(attributes.getBoolean("readOnly")); // 获取注解上的value属性值 rbta.setQualifier(attributes.getString("value")); ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>(); // 获取注解上的rollbackFor属性列表 Class<?>[] rbf = attributes.getClassArray("rollbackFor"); for (Class<?> rbRule : rbf) { RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule); rollBackRules.add(rule); } // 获取注解上的rollbackForClassName属性列表 String[] rbfc = attributes.getStringArray("rollbackForClassName"); for (String rbRule : rbfc) { RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule); rollBackRules.add(rule); } // 获取注解上的noRollbackFor属性列表 Class<?>[] nrbf = attributes.getClassArray("noRollbackFor"); for (Class<?> rbRule : nrbf) { NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule); rollBackRules.add(rule); } // 获取注解上的noRollbackForClassName属性列表 String[] nrbfc = attributes.getStringArray("noRollbackForClassName"); for (String rbRule : nrbfc) { NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule); rollBackRules.add(rule); } rbta.getRollbackRules().addAll(rollBackRules); return rbta; }
能够看到,对因而否须要进行事务逻辑的环绕的判断很是简单,就只是判断目标方法上是否包含有@Transactional
注解,若是存在,则解析其各个属性值,封装为TransactionAttribute对象,而后返回。
本文主要讲解Spring是如何判断目标方法是否须要进行事务切面逻辑环绕的,而且讲解了Spring是如何解析@Transactional
注解中各个属性值的。能够看到,若是目标方法或其所在类标注了@Transactional
注解,则该方法就会被事务逻辑环绕。