美文网首页
Spring源码解析之AOP上

Spring源码解析之AOP上

作者: lkuuuuuun | 来源:发表于2019-04-08 23:35 被阅读0次

    我们知道面向对象编程(OOP)有一些弊端,即在不同对象(不具有继承关系)中引入一个公共行为时,例如日志,安全检测等我们不得不在不同对象中都引入公共行为,这样就造成了代码冗余,难以维护.所以就有了对面向对象编程的补充:面向切面编程(AOP).
    本文我们以注解的使用方式为例,分析其相关源码

    Spring 支持aop注解是添加<aop:aspectj-autoproxy.>标签配置, 我们将从AopNamespaceHandler类为入口进行剖析.

    public class AopNamespaceHandler extends NamespaceHandlerSupport {
    
        /**
         * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
         * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
         * and '{@code scoped-proxy}' tags.
         */
        @Override
        public void init() {
            // In 2.0 XSD as well as in 2.1 XSD.
            registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
            registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
            registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
    
            // Only in 2.0 XSD: moved to context namespace as of 2.1
            registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        }
    
    }
    

    发现在初始化过程中注册了AspectJAutoProxyBeanDefinitionParser解析器,我们看看该解析器的内部实现,

        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
            extendBeanDefinition(element, parserContext);
            return null;
        }
    

    继续追踪 发现是注册了AnnotationAwareAspectJAutoProxyCreator类

        public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
            return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
        }
    
    image.png

    通过AnnotationAwareAspectJAutoProxyCreator的UML类图可以看到该creator实现了BeanPostProcessor后处理器接口
    则我们将思路放在后处理器的方法postProcessAfterInitialization()中,查询后发现该方法的实现是在AbstractAutoProxyCreator抽象类中

    /**
         * Create a proxy with the configured interceptors if the bean is
         * identified as one to proxy by the subclass.
         * @see #getAdvicesAndAdvisorsForBean
         */
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean != null) {
                Object cacheKey = getCacheKey(bean.getClass(), beanName);
                if (!this.earlyProxyReferences.contains(cacheKey)) {
                    return wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
            return bean;
        }
    

    首先有个是否是正在创建中的判断,之后便调用wrapIfNecessary()方法

        /**
         * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
         * @param bean the raw bean instance
         * @param beanName the name of the bean
         * @param cacheKey the cache key for metadata access
         * @return a proxy wrapping the bean, or the raw bean instance as-is
         */
        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;
            }
                // 给定的bean是不是基础设施类,或者设置了指定的bean不需要代理
            if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
    
            // 如果存在增强的方法 则进行代理.
            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;
        }
    

    在函数中 我们已经看到了创建代理的雏形,而真正创建的代理的代码是从getAdvicesAndAdvisorsForBean开始的.
    创建代理主要包含2个步骤:
    1.获取增强方法或者增强器
    2.根据获取的增强器进行代理
    我们深入代码继续解析
    1.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();
        }
    

    发现真正获取增强器的逻辑在findEligibleAdvisors()中

        /**
         * Find all eligible Advisors for auto-proxying this class.
         * @param beanClass the clazz to find advisors for
         * @param beanName the name of the currently proxied bean
         * @return the empty List, not {@code null},
         * if there are no pointcuts or interceptors
         * @see #findCandidateAdvisors
         * @see #sortAdvisors
         * @see #extendAdvisors
         */
        protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
                  // 在BeanFactory中获取所有的候选增强器
            List<Advisor> candidateAdvisors = findCandidateAdvisors();
                // 将获取到所有的增强器进行匹配 返回可用的增强器
            List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
            extendAdvisors(eligibleAdvisors);
            if (!eligibleAdvisors.isEmpty()) {
                eligibleAdvisors = sortAdvisors(eligibleAdvisors);
            }
            return eligibleAdvisors;
        }
    
        @Override
        protected List<Advisor> findCandidateAdvisors() {
            // 因为这是使用注解的方式配置aop方式  所以这里也要调用父类方法获取xml中配置的增强器
            List<Advisor> advisors = super.findCandidateAdvisors();
            // 获取bean注解增强的增强器
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
            return advisors;
        }
    
        /**
         * Find all candidate Advisors to use in auto-proxying.
         * @return the List of candidate Advisors
         */
        protected List<Advisor> findCandidateAdvisors() {
            return this.advisorRetrievalHelper.findAdvisorBeans();
        }
    
        /**
         * Find all eligible Advisor beans in the current bean factory,
         * ignoring FactoryBeans and excluding beans that are currently in creation.
         * @return the list of {@link org.springframework.aop.Advisor} beans
         * @see #isEligibleBean
         */
        public List<Advisor> findAdvisorBeans() {
            // Determine list of advisor bean names, if not cached already.
            String[] advisorNames = this.cachedAdvisorBeanNames;
            if (advisorNames == null) {
                // Do not initialize FactoryBeans here: We need to leave all regular beans
                // uninitialized to let the auto-proxy creator apply to them!
                advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Advisor.class, true, false);
                this.cachedAdvisorBeanNames = advisorNames;
            }
            if (advisorNames.length == 0) {
                return new ArrayList<Advisor>();
            }
    
            List<Advisor> advisors = new ArrayList<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;
        }
    

    该方法的逻辑很清楚,首先从BeanFactory中获取所有的增强器beanName,再通过BeanFactory的getBean获取真正的增强器实例
    我们继续看获取通过注解配置的增强器this.aspectJAdvisorsBuilder.buildAspectJAdvisors()

        /**
         * Look for AspectJ-annotated aspect beans in the current bean factory,
         * and return to a list of Spring AOP Advisors representing them.
         * <p>Creates a Spring Advisor for each AspectJ advice method.
         * @return the list of {@link org.springframework.aop.Advisor} beans
         * @see #isEligibleBean
         */
        public List<Advisor> buildAspectJAdvisors() {
            List<String> aspectNames = this.aspectBeanNames;
    
            if (aspectNames == null) {
                synchronized (this) {
                    aspectNames = this.aspectBeanNames;
                    if (aspectNames == null) {
                        List<Advisor> advisors = new LinkedList<Advisor>();
                        aspectNames = new LinkedList<String>();
                                        // 获取所有的beanName
                        String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                                this.beanFactory, Object.class, true, false);
                                          // 进行遍历
                        for (String beanName : beanNames) {
                                                // 判断是否符合 <aop:include />的配置
                            if (!isEligibleBean(beanName)) {
                                continue;
                            }
                            // We must be careful not to instantiate beans eagerly as in this case they
                            // would be cached by the Spring container but would not have been weaved.
                            Class<?> beanType = this.beanFactory.getType(beanName);
                            if (beanType == null) {
                                continue;
                            }
                                                  // 通过beanType判断是否有Aspect注解
                            if (this.advisorFactory.isAspect(beanType)) {
                                aspectNames.add(beanName);
                                AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        // 单例
                                if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                    MetadataAwareAspectInstanceFactory factory =
                                            new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                    List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                    if (this.beanFactory.isSingleton(beanName)) {
                                        this.advisorsCache.put(beanName, classAdvisors);
                                    }
                                    else {
                                        this.aspectFactoryCache.put(beanName, factory);
                                    }
                                    advisors.addAll(classAdvisors);
                                }
                                else {
                                    // Per target or per this.
                                    if (this.beanFactory.isSingleton(beanName)) {
                                        throw new IllegalArgumentException("Bean with name '" + beanName +
                                                "' is a singleton, but aspect instantiation model is not singleton");
                                    }
                                                                // 原型
                                    MetadataAwareAspectInstanceFactory factory =
                                            new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                                    this.aspectFactoryCache.put(beanName, factory);
                                    advisors.addAll(this.advisorFactory.getAdvisors(factory));
                                }
                            }
                        }
                        this.aspectBeanNames = aspectNames;
                        return advisors;
                    }
                }
            }
    
            if (aspectNames.isEmpty()) {
                return Collections.emptyList();
            }
            List<Advisor> advisors = new LinkedList<Advisor>();
            for (String aspectName : aspectNames) {
                List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
                if (cachedAdvisors != null) {
                    advisors.addAll(cachedAdvisors);
                }
                else {
                    MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
                    advisors.addAll(this.advisorFactory.getAdvisors(factory));
                }
            }
            return advisors;
        }
    

    获取注解增强器的方法虽然长,但是逻辑却比较清楚,首先获取所有的beanName,过滤不符合include配置的,然后通过beanType判断是否有Aspect注解,然后 this.advisorFactory.getAdvisors(factory)获取classAdvisors 增强器

            @Override
            protected boolean isEligibleBean(String beanName) {
                return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName);
            }
    
        /**
         * Check whether the given aspect bean is eligible for auto-proxying.
         * <p>If no &lt;aop:include&gt; elements were used then "includePatterns" will be
         * {@code null} and all beans are included. If "includePatterns" is non-null,
         * then one of the patterns must match.
         */
        protected boolean isEligibleAspectBean(String beanName) {
            if (this.includePatterns == null) {
                return true;
            }
            else {
                for (Pattern pattern : this.includePatterns) {
                    if (pattern.matcher(beanName).matches()) {
                        return true;
                    }
                }
                return false;
            }
        }
    

    这里的includePatterns就是文章开始解析<aop:aspectj-autoproxy/>子标签<aop:include/>的配置时织入的,有兴趣的读者可以了解一下具体用法,这里不多赘述。
    我们继续看判断是否有@aspect注解的逻辑

        /**
         * We consider something to be an AspectJ aspect suitable for use by the Spring AOP system
         * if it has the @Aspect annotation, and was not compiled by ajc. The reason for this latter test
         * is that aspects written in the code-style (AspectJ language) also have the annotation present
         * when compiled by ajc with the -1.5 flag, yet they cannot be consumed by Spring AOP.
         */
        @Override
        public boolean isAspect(Class<?> clazz) {
            return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
        }
    
        private boolean hasAspectAnnotation(Class<?> clazz) {
            return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
        }
    
    

    List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

        @Override
        public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
            Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
            String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
            validate(aspectClass);
    
            // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
            // so that it will only instantiate once.
            MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
                    new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
    
            List<Advisor> advisors = new ArrayList<Advisor>();
            for (Method method : getAdvisorMethods(aspectClass)) {  // 获取方法 其中过滤了带有@pointcut注解的方法
                      // 获取增强器
                Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
                if (advisor != null) {
                    advisors.add(advisor);
                }
            }
    
            // If it's a per target aspect, emit the dummy instantiating aspect.
            if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
                Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
                advisors.add(0, instantiationAdvisor);
            }
    
            // Find introduction fields.
            for (Field field : aspectClass.getDeclaredFields()) {
                Advisor advisor = getDeclareParentsAdvisor(field);
                if (advisor != null) {
                    advisors.add(advisor);
                }
            }
    
            return advisors;
        }
    

    getAdvisorMethods方法的逻辑是获取该类的方法,其中过滤了带有@pointcut注解的方法,并按照比较器进行了排序()

        private List<Method> getAdvisorMethods(Class<?> aspectClass) {
            final List<Method> methods = new ArrayList<Method>();
            ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
                @Override
                public void doWith(Method method) throws IllegalArgumentException {
                    // Exclude pointcuts
                    if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                        methods.add(method);
                    }
                }
            });
            Collections.sort(methods, METHOD_COMPARATOR);
            return methods;
        }
    
        private static final Comparator<Method> METHOD_COMPARATOR;
    
        static {
            CompoundComparator<Method> comparator = new CompoundComparator<Method>();
            comparator.addComparator(new ConvertingComparator<Method, Annotation>(
                    new InstanceComparator<Annotation>(
                            Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
                    new Converter<Method, Annotation>() {
                        @Override
                        public Annotation convert(Method method) {
                            AspectJAnnotation<?> annotation =
                                    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
                            return (annotation != null ? annotation.getAnnotation() : null);
                        }
                    }));
            comparator.addComparator(new ConvertingComparator<Method, String>(
                    new Converter<Method, String>() {
                        @Override
                        public String convert(Method method) {
                            return method.getName();
                        }
                    }));
            METHOD_COMPARATOR = comparator;
        }
    

    可以看到增强器的优先级顺序为 @Around>@Before>@After>@AfterReturn>@AfterThrowing

    我们具体来看获取增强器的方法

        @Override
        public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
                int declarationOrderInAspect, String aspectName) {
    
            validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
              // 切入点信息的获取
            AspectJExpressionPointcut expressionPointcut = getPointcut(
                    candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
            if (expressionPointcut == null) {
                return null;
            }
        // 实例化增强器
            return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                    this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
        }
    
        private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
                  // 获取方法上的注解
            AspectJAnnotation<?> aspectJAnnotation =
                    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);  
            if (aspectJAnnotation == null) {
                return null;
            }
              // 获取注解上的execution表达式
            AspectJExpressionPointcut ajexp =
                    new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
            ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
            ajexp.setBeanFactory(this.beanFactory);
            return ajexp;
        }
    
        /**
         * Find and return the first AspectJ annotation on the given method
         * (there <i>should</i> only be one anyway...).
         */
        @SuppressWarnings("unchecked")
        protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
            for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
                AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
                if (foundAnnotation != null) {
                    return foundAnnotation;
                }
            }
            return null;
        }
    
    
        private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
                Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
    

    来看看实例化增强器的逻辑 这个构造方法重点在instantiateAdvice()方法上,该方法将不同的增强器注解实例化对应的增强器实例

        public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
                Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
                MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    
            this.declaredPointcut = declaredPointcut;
            this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
            this.methodName = aspectJAdviceMethod.getName();
            this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
            this.aspectJAdviceMethod = aspectJAdviceMethod;
            this.aspectJAdvisorFactory = aspectJAdvisorFactory;
            this.aspectInstanceFactory = aspectInstanceFactory;
            this.declarationOrder = declarationOrder;
            this.aspectName = aspectName;
    
            if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
                // Static part of the pointcut is a lazy type.
                Pointcut preInstantiationPointcut = Pointcuts.union(
                        aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
    
                // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
                // If it's not a dynamic pointcut, it may be optimized out
                // by the Spring AOP infrastructure after the first evaluation.
                this.pointcut = new PerTargetInstantiationModelPointcut(
                        this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
                this.lazy = true;
            }
            else {
                // A singleton aspect.
                this.pointcut = this.declaredPointcut;
                this.lazy = false;
                    // 实例化增强器
                this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
            }
        }
    
        private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
            return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
                    this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
        }
    
    
          @Override
        public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
                MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    
            Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
            validate(candidateAspectClass);
    
            AspectJAnnotation<?> aspectJAnnotation =
                    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
            if (aspectJAnnotation == null) {
                return null;
            }
    
            // If we get here, we know we have an AspectJ method.
            // Check that it's an AspectJ-annotated class
            if (!isAspect(candidateAspectClass)) {
                throw new AopConfigException("Advice must be declared inside an aspect type: " +
                        "Offending method '" + candidateAdviceMethod + "' in class [" +
                        candidateAspectClass.getName() + "]");
            }
    
            if (logger.isDebugEnabled()) {
                logger.debug("Found AspectJ method: " + candidateAdviceMethod);
            }
    
            AbstractAspectJAdvice springAdvice;
              // 根据不同的注解匹配对应的增强器
            switch (aspectJAnnotation.getAnnotationType()) {
                case AtPointcut:
                    if (logger.isDebugEnabled()) {
                        logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                    }
                    return null;
                case AtAround:
                    springAdvice = new AspectJAroundAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtBefore:
                    springAdvice = new AspectJMethodBeforeAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtAfter:
                    springAdvice = new AspectJAfterAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtAfterReturning:
                    springAdvice = new AspectJAfterReturningAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                    if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                        springAdvice.setReturningName(afterReturningAnnotation.returning());
                    }
                    break;
                case AtAfterThrowing:
                    springAdvice = new AspectJAfterThrowingAdvice(
                            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                    if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                        springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                    }
                    break;
                default:
                    throw new UnsupportedOperationException(
                            "Unsupported advice type on method: " + candidateAdviceMethod);
            }
    
            // Now to configure the advice...
            springAdvice.setAspectName(aspectName);
            springAdvice.setDeclarationOrder(declarationOrder);
            String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
            if (argNames != null) {
                springAdvice.setArgumentNamesFromStringArray(argNames);
            }
            springAdvice.calculateArgumentBindings();
    
            return springAdvice;
        }
    

    到这里aop注解方式获取到了所有的候选增强器,下面要匹配适用于当前bean的增强器:

        /**
         * Search the given candidate Advisors to find all Advisors that
         * can apply to the specified bean.
         * @param candidateAdvisors the candidate Advisors
         * @param beanClass the target's bean class
         * @param beanName the target's bean name
         * @return the List of applicable Advisors
         * @see ProxyCreationContext#getCurrentProxiedBeanName()
         */
        protected List<Advisor> findAdvisorsThatCanApply(
                List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    
            ProxyCreationContext.setCurrentProxiedBeanName(beanName);
            try {
                return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
            }
            finally {
                ProxyCreationContext.setCurrentProxiedBeanName(null);
            }
        }
    
        /**
         * Determine the sublist of the {@code candidateAdvisors} list
         * that is applicable to the given class.
         * @param candidateAdvisors the Advisors to evaluate
         * @param clazz the target class
         * @return sublist of Advisors that can apply to an object of the given class
         * (may be the incoming List as-is)
         */
        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) {
                    // already processed
                    continue;
                }
                if (canApply(candidate, clazz, hasIntroductions)) {
                    eligibleAdvisors.add(candidate);
                }
            }
            return eligibleAdvisors;
        }
    

    上面的代码分为引介增强器和非引介增强2个逻辑,引介增强器是属于特殊的一类增强器,它的切入点不在方法而是在类上,可以为指定的类添加某些方法或者属性,通过引介增强,我们可以为目标类添加一个接口的实现,即原来目标类未实现某个接口,通过引介增强可以为目标类创建实现该接口的代理,具体的处理都是在重载的canApply()方法中

        /**
         * Can the given advisor apply at all on the given class?
         * <p>This is an important test as it can be used to optimize out a advisor for a class.
         * This version also takes into account introductions (for IntroductionAwareMethodMatchers).
         * @param advisor the advisor to check
         * @param targetClass class we're testing
         * @param hasIntroductions whether or not the advisor chain for this bean includes
         * any introductions
         * @return whether the pointcut can apply on any method
         */
        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) {
                PointcutAdvisor pca = (PointcutAdvisor) advisor;
                return canApply(pca.getPointcut(), targetClass, hasIntroductions);
            }
            else {
                // It doesn't have a pointcut so we assume it applies.
                return true;
            }
        }
    
    

    前文我们已经分析到实例化的增强器advisor 为InstantiationModelAwarePointcutAdvisorImpl,我们追踪看pca.getPointcut()方法,这个方法的返回值就是我们看到的在InstantiationModelAwarePointcutAdvisorImpl初始化时传入的AspectJExpressionPointcut,我们以AspectJExpressionPointcut作为第一个参数继续跟踪canApply方法:

        /**
         * Can the given pointcut apply at all on the given class?
         * <p>This is an important test as it can be used to optimize
         * out a pointcut for a class.
         * @param pc the static or dynamic pointcut to check
         * @param targetClass the class to test
         * @param hasIntroductions whether or not the advisor chain
         * for this bean includes any introductions
         * @return whether the pointcut can apply on any method
         */
        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;
            }
    
            MethodMatcher methodMatcher = pc.getMethodMatcher();
            if (methodMatcher == MethodMatcher.TRUE) {
                // No need to iterate the methods if we're matching any method anyway...
                return true;
            }
    
            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 = ReflectionUtils.getAllDeclaredMethods(clazz);
                for (Method method : methods) {
                    if ((introductionAwareMethodMatcher != null &&
                            introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
                            methodMatcher.matches(method, targetClass)) {
                        return true;
                    }
                }
            }
    
            return false;
        }
    

    MethodMatcher methodMatcher = pc.getMethodMatcher()
    查看代码发现返回的方法匹配器是该AspectJExpressionPointcut本身

        @Override
        public MethodMatcher getMethodMatcher() {
            checkReadyToMatch();
            return this;
        }
    
    AspectJExpressionPointcut类继承图.png

    可以看到,将增强器与当前类方法是否匹配的任务交给了AspectJExpressionPointcut的match()方法

        @Override
        public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
            checkReadyToMatch();
            Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
            ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
    
            // Special handling for this, target, @this, @target, @annotation
            // in Spring - we can optimize since we know we have exactly this class,
            // and there will never be matching subclass at runtime.
            if (shadowMatch.alwaysMatches()) {
                return true;
            }
            else if (shadowMatch.neverMatches()) {
                return false;
            }
            else {
                // the maybe case
                if (beanHasIntroductions) {
                    return true;
                }
                // A match test returned maybe - if there are any subtype sensitive variables
                // involved in the test (this, target, at_this, at_target, at_annotation) then
                // we say this is not a match as in Spring there will never be a different
                // runtime subtype.
                RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
                return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
            }
        }
    

    getShadowMatch方法里面就是调用aspectj提供的api来判断当前类是否满足execution表达式的规则,有兴趣的读者可以查阅aspect的相关资料进行学习。再回看前面的wrapIfNecessary()代码,获取了所有bean匹配的增强器之后,就可以创建代理了,即createProxy()方法逻辑

        /**
         * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
         * @param bean the raw bean instance
         * @param beanName the name of the bean
         * @param cacheKey the cache key for metadata access
         * @return a proxy wrapping the bean, or the raw bean instance as-is
         */
        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;
        }
    
        /**
         * Create an AOP proxy for the given bean.
         * @param beanClass the class of the bean
         * @param beanName the name of the bean
         * @param specificInterceptors the set of interceptors that is
         * specific to this bean (may be empty, but not null)
         * @param targetSource the TargetSource for the proxy,
         * already pre-configured to access the bean
         * @return the AOP proxy for the bean
         * @see #buildAdvisors
         */
        protected Object createProxy(
                Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
            if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
                AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
            }
    
            ProxyFactory proxyFactory = new ProxyFactory();
            proxyFactory.copyFrom(this);
    
            if (!proxyFactory.isProxyTargetClass()) {
                if (shouldProxyTargetClass(beanClass, beanName)) { // <target-proxy-class /> 配置
                    proxyFactory.setProxyTargetClass(true);
                }
                else {
                    evaluateProxyInterfaces(beanClass, proxyFactory);
                }
            }
    
            Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); 
            proxyFactory.addAdvisors(advisors);   // 添加增强器
            proxyFactory.setTargetSource(targetSource);
            customizeProxyFactory(proxyFactory);  // 模板方法
    
            proxyFactory.setFrozen(this.freezeProxy);
            if (advisorsPreFiltered()) {
                proxyFactory.setPreFiltered(true);
            }
    
            return proxyFactory.getProxy(getProxyClassLoader());
        }
    

    核心的处理在proxyFactory.getProxy(getProxyClassLoader());

        /**
         * Create a new proxy according to the settings in this factory.
         * <p>Can be called repeatedly. Effect will vary if we've added
         * or removed interfaces. Can add and remove interceptors.
         * <p>Uses the given class loader (if necessary for proxy creation).
         * @param classLoader the class loader to create the proxy with
         * (or {@code null} for the low-level proxy facility's default)
         * @return the proxy object
         */
        public Object getProxy(ClassLoader classLoader) {
            return createAopProxy().getProxy(classLoader);
        }
    
    
        /**
         * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
         * create an AOP proxy with {@code this} as an argument.
         */
        protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(this);
        }
    
        @Override
        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
                Class<?> targetClass = config.getTargetClass();
                if (targetClass == null) {
                    throw new AopConfigException("TargetSource cannot determine target class: " +
                            "Either an interface or a target is required for proxy creation.");
                }
                if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                    return new JdkDynamicAopProxy(config);
                }
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }
    

    终于看到了我们心心念的aop创建代理的方式:
    从上面代码可以看到第一个if的3个条件判断分别为:
    是否使用cglib时进行激进的优化方式
    是否配置<proxy-target-class />强制使用cglib进行代理
    是否没有接口

    第二个if的2个条件判断分别为
    目标类是否是接口
    目标类是否由Spring创建的代理类

    所以Spring aop进行代理时逻辑已经很明了了,如果没有第一个if 的3个条件则使用JDK动态代理,否则进行第二个if判断,如果该类本身就是接口或者是Spring生成的代理类,则还使用JDK动态代理,否则使用cglib进行代理。
    由于文章的字数限制,2种代理具体的实现方式请接下文。

    相关文章

      网友评论

          本文标题:Spring源码解析之AOP上

          本文链接:https://www.haomeiwen.com/subject/layqiqtx.html