• Spring事务解析3-增强方法的获取


    从InfrastructureAdvisorAutoProxyCreator的层次结构中可以看到,InfrastructureAdvisorAutoProxyCreator间接实现了SmartInstantiationAwareBeanPostProcessor,而SmartInstantiationAwareBeanPostProcessor又继承自InstantiationAwareBeanPostProcessor,也就是说在Spring中,所有bean实例化时Spring都会保证调用其postProcessAfterInitialization方法,其实现是在父类AbstractAutoProxyCreator类中实现。

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean != null) {
                //根据给定的bean的class和name构建出个key,beanClassName_beanName
           Object cacheKey = getCacheKey(bean.getClass(), beanName);
           //是否是由于避免循环依赖而创建的bean代理
                if (!this.earlyProxyReferences.contains(cacheKey)) {
                    return wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
            return bean;
        }

    这里实现的主要目的是对指定bean进行封装,当然首先要确定是否需要封装,检测及封装的工作都委托给了wrapIfNecessary函数进行。

        protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
         //如果已经处理过
            if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
                return bean;
            }
            if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
                return bean;
            }
            if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
            // Create proxy if we have advice.
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                Object proxy = createProxy(
                        bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            }
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

    wrapIfNecessary函数功能实现起来很复杂,但是逻辑上理解起来还是相对简单的,在wrapIfNecessary函数中主要的工作如下。

    (1)找出指定bean对应的增强器。

    (2)根据找出的增强器创建代理。

    获取对应class/method的增强器

    获取指定bean对应的增强器,其中包含两个关键字:增强器与对应。也就是说在getAdvicesAndAdvisorsForBean函数中,不但要找出增强器,而且还需要判断增强器是否满足要求。

        @Override
        protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
            List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
            if (advisors.isEmpty()) {
                return DO_NOT_PROXY;
            }
            return advisors.toArray();
        }
    
        protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
            List<Advisor> candidateAdvisors = findCandidateAdvisors();
            List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
            extendAdvisors(eligibleAdvisors);
            if (!eligibleAdvisors.isEmpty()) {
                eligibleAdvisors = sortAdvisors(eligibleAdvisors);
            }
            return eligibleAdvisors;
        }

    渐渐地体会到了 Spring 中代码的优秀,即使是一个很复杂的逻辑,在 Spring中也会被拆分成若干个小的逻辑,然后在每个函数中实现,使得每个函数的逻辑简单到我们能快速地理解,而不会像有些人开发的那样,将一大堆的逻辑都罗列在一个函数中,给后期维护人员造成巨大的困扰。

    同样,通过上面的函数,Spring又将任务进行了拆分,分成了获取所有增强器增强器是否匹配两个功能点。

    寻找候选增强器

        protected List<Advisor> findCandidateAdvisors() {
            return this.advisorRetrievalHelper.findAdvisorBeans();
        }
        public List<Advisor> findAdvisorBeans() {
            String[] advisorNames = null;
            synchronized (this) {
                advisorNames = this.cachedAdvisorBeanNames;
                if (advisorNames == null) {
                    advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Advisor.class, true, false);
                    this.cachedAdvisorBeanNames = advisorNames;
                }
            }
            if (advisorNames.length == 0) {
                return new LinkedList<Advisor>();
            }
            List<Advisor> advisors = new LinkedList<Advisor>();
            for (String name : advisorNames) {
                if (isEligibleBean(name)) {
                    if (this.beanFactory.isCurrentlyInCreation(name)) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Skipping currently created advisor '" + name + "'");
                        }
                    }
                    else {
                        try {
                            advisors.add(this.beanFactory.getBean(name, Advisor.class));
                        }
                        catch (BeanCreationException ex) {
                            Throwable rootCause = ex.getMostSpecificCause();
                            if (rootCause instanceof BeanCurrentlyInCreationException) {
                                BeanCreationException bce = (BeanCreationException) rootCause;
                                if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
                                    if (logger.isDebugEnabled()) {
                                        logger.debug("Skipping advisor '" + name +
                                                "' with dependency on currently created bean: " + ex.getMessage());
                                    }
                                    // Ignore: indicates a reference back to the bean we're trying to advise.
                                    // We want to find advisors other than the currently created bean itself.
                                    continue;
                                }
                            }
                            throw ex;
                        }
                    }
                }
            }
            return advisors;
        }

    首先是通过BeanFactoryUtils类提供的工具方法获取所有对应Advisor.class的类,获取办法无非是使用ListableBeanFactory中提供的方法:

    String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit);

    而当我们知道增强器在容器中的beanName时,获取增强器已经不是问题了,在BeanFactory中提供了这样的方法,可以帮助我们快速定位对应的bean实例。

    T getBean(String name, Class requiredType) throws BeansException;

    自定义标签曾经注册了一个类型为BeanFactoryTransactionAttributeSourceAdvisor的bean,而在此bean中我们又注入了另外两个Bean,那么此时这个Bean就会被开始使用了。因为BeanFactoryTransactionAttributeSourceAdvisor同样也实现了Advisor接口,那么在获取所有增强器时自然也会将此bean提取出来,并随着其他增强器一起在后续的步骤中被织入代理。

    候选增强器中寻找到匹配项

        protected List<Advisor> findAdvisorsThatCanApply(
                List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    
            ProxyCreationContext.setCurrentProxiedBeanName(beanName);
            try {
                return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
            }
            finally {
                ProxyCreationContext.setCurrentProxiedBeanName(null);
            }
        }
        public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
            if (candidateAdvisors.isEmpty()) {
                return candidateAdvisors;
            }
         //首先处理引介增强 List
    <Advisor> eligibleAdvisors = new LinkedList<Advisor>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { //引介增强已经处理 continue; }
           //对于普通bean的处理
    if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } public static boolean canApply(Advisor advisor, Class<?> targetClass) { return canApply(advisor, targetClass, false); } public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) {
           //当前的advisor就是之前查找出来的类型为BeanFactoryTransactionAttributeSourceAdvisor的bean实例,
           //而通过类的层次结构我们又知道:BeanFactoryTransactionAttributeSourceAdvisor间接实现了PointcutAdvisor。
           //因此,在canApply函数中的第二个if判断if (advisor instanceof PointcutAdvisor)时就会通过判断,
           //会将BeanFactoryTransactionAttributeSourceAdvisor中的getPointcut()方法返回值作为参数继续调用canApply方法,
           //而getPoint()方法返回的是TransactionAttributeSourcePointcut类型的实例。见下面BeanFactoryTransactionAttributeSourceAdvisor.java
           //对于transactionAttributeSource这个属性是在解析自定义标签时注入进去的,见标签解析。 PointcutAdvisor pca
    = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } } public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); if (!pc.getClassFilter().matches(targetClass)) { return false; }
         //此时的pc表示TransactionAttributeSourcePointcut,pc.getMethodMatcher()返回的正是自身(this).  MethodMatcher methodMatcher
    = pc.getMethodMatcher(); IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; }
         //首先获取对应类的所有接口并连同类本身一起遍历 Set
    <Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) {
           //遍历过程中又对类中的方法再次遍历 Method[] methods
    = clazz.getMethods(); for (Method method : methods) {
              //一旦匹配成功便认为这个类适用于当前增强器。
    if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || methodMatcher.matches(method, targetClass)) { return true; } } } return false; }

    BeanFactoryTransactionAttributeSourceAdvisor.java
    public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
      private TransactionAttributeSource transactionAttributeSource;
      private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
        @Override
        protected TransactionAttributeSource getTransactionAttributeSource() {
          return transactionAttributeSource;
        }
      };
    }

    对于事务的配置不仅仅局限于在函数上配置,我们都知道,在类活接口上的配置可以延续到类中的每个函数,那么,如果针对每个函数进行检测,在类本身上配置的事务属性岂不是检测不到了吗?带着这个疑问,我们继续探求matcher方法。做匹配的时候methodMatcher.matches(method, targetClass)会使用TransactionAttributeSource Pointcut类的matches方法。

        @Override
        public boolean matches(Method method, Class<?> targetClass) {
            if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
                return false;
            }
         //自定义标签解析时注入,AnnotationTransactionAttributeSource TransactionAttributeSource tas
    = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
       //AnnotationTransactionAttributeSource.java @Override
    public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) { // First, see if we have a cached value. Object cacheKey = getCacheKey(method, targetClass); Object 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 (TransactionAttribute) cached; } } else { // We need to work it out. TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass); // Put it in the cache. if (txAtt == null) { this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { if (logger.isDebugEnabled()) { Class<?> classToLog = (targetClass != null ? targetClass : method.getDeclaringClass()); logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." + method.getName() + "' with attribute: " + txAtt); } this.attributeCache.put(cacheKey, txAtt); } return txAtt; } }

    很遗憾,在getTransactionAttribute函数中并没有找到我们想要的代码,没有找到在类活接口上的配置可以延续到类中的每个函数的逻辑,这里是指常规的一贯的套路。尝试从缓存加载,如果对应信息没有被缓存的话,工作又委托给了computeTransactionAttribute函数,在computeTransactionAttribute函数中终于的我们看到了事务标签的提取过程。

        protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
            // Don't allow no-public methods as required.
            if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
                return null;
            }
            // Ignore CGLIB subclasses - introspect the actual user class.
            Class<?> userClass = ClassUtils.getUserClass(targetClass);
            //method代表接口中的方法,specificMethod代表实现类中的方法
            Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
            // If we are dealing with method with generic parameters, find the original method.
            specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
         //查看实现方法中是否存在事务声明
            TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
            if (txAtt != null) {
                return txAtt;
            }
            //查看方法所在类中是否存在事务声明
            txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
            if (txAtt != null) {
                return txAtt;
            }
         //如果存在接口,则到接口中去寻找
            if (specificMethod != method) {
                //查找接口方法是否存在事务声明
                txAtt = findTransactionAttribute(method);
                if (txAtt != null) {
                    return txAtt;
                }
                //查看接口所在类上面是否存在事务声明
                return findTransactionAttribute(method.getDeclaringClass());
            }
            return null;
        }

    如果方法中存在事务属性,则使用方法上的属性,否则使用方法所在的类上的属性,如果方法所在类的属性上还是没有搜寻到对应的事务属性,那么再搜寻接口中的方法,再没有的话,最后尝试搜寻接口的类上面的声明。对于函数computeTransactionAttribute中的逻辑与我们所认识的规则并无差别,但是上面函数中并没有真正的去做搜寻事务属性的逻辑,而是搭建了个执行框架,将搜寻事务属性的任务委托给了findTransactionAttribute方法去执行。

        @Override
        protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
            return determineTransactionAttribute(clazz);
        }
        protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
            if (ae.getAnnotations().length > 0) {
                //this.annotationParsers是在当前类AnnotationTransactionAttributeSource初始化的时候初始化的,
           //其中的值被加入了SpringTransactionAnnotationParser,
    //也就是当进行属性获取的时候其实是使用SpringTransactionAnnotationParser类的parseTransactionAnnotation方法进行解析的。 for (TransactionAnnotationParser annotationParser : this.annotationParsers) { TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae); if (attr != null) { return attr; } } } return null; } //首先会判断当前的类是否含有Transactional注解,这是事务属性的基础,当然如果有的话会继续调用parseTransactionAnnotation方法解析详细的属性。 @Override public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) { AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class); if (attributes != null) { return parseTransactionAnnotation(attributes); } else { return null; } } protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) { RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); Propagation propagation = attributes.getEnum("propagation"); //解析propagation rbta.setPropagationBehavior(propagation.value()); Isolation isolation = attributes.getEnum("isolation"); //解析isolation rbta.setIsolationLevel(isolation.value()); //解析timeout rbta.setTimeout(attributes.getNumber("timeout").intValue()); //解析readOnly rbta.setReadOnly(attributes.getBoolean("readOnly")); //解析value rbta.setQualifier(attributes.getString("value")); //解析rollbackFor ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>(); 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; }

    上面方法中实现了对对应类或者方法的事务属性解析,你会在这个类中看到任何你常用或者不常用的属性提取。

    找出某个增强器是否适合于对应的类,而是否匹配的关键则在于是否从指定的类或类中的方法中找到对应的事务属性,这个任务至此是完成了。在,我们以UserServiceImpl为例,已经在它的接口UserService中找到了事务属性,所以,它是与事务增强器匹配的,也就是它会被事务功能修饰。

    当判断某个bean适用于事务增强时,也就是适用于增强器BeanFactoryTransactionAttributeSourceAdvisor,然后执行最上面的return advisors.toArray();返回,至此完成了Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);增强器的获取。

  • 相关阅读:
    js Bom Dom
    2019西安多校联训 Day1
    数论——扩展欧几里德
    MySQL InnoDB引擎行格式、数据页简析
    centos7安装ansible并简单设置k8s集群节点hosts文件
    Redis缓存穿透和雪崩
    Redis主从复制——哨兵模式
    Redis主从复制——非哨兵模式
    Redis发布订阅
    Redis持久化——RDB与AOF
  • 原文地址:https://www.cnblogs.com/wade-luffy/p/6080533.html
Copyright © 2020-2023  润新知