• 创建AOP代理(上篇)


    前言

    上一篇文章动态AOP自定义标签讲解了自定义配置完成了对AnnotationAwareAspectJAutoProxyCreator类型的自动注册,那么这个类型到底做了什么工作来完成AOP的操作呢?来看一下AnnotationAwareAspectJAutoProxyCreator类UML图:

    从上图的类图中可以看出,AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor接口,而实现了BeanPostProcessor后,当Spring加载这个bean时会在实例化前调用其postProcessAfterInitialization方法,而对于AOP的分析也由此开始。

    创建AOP代理

    在父类AbstractAutoProxyCreator的postProcessAfterInitialization中代码如下:

    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
            if (bean != null) {
                //根据给定的bean的class和name构造作为key,格式为:beanClassName_beanName
                Object cacheKey = getCacheKey(bean.getClass(), beanName);
                if (!this.earlyProxyReferences.contains(cacheKey)) {
                    //如果适合做代理,则需要做封装
                    return wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
            return bean;
        }
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
            //如果已经处理过
            if (StringUtils.hasLength(beanName) && 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;
        }

    函数中我们已经看到了代理的雏形。当然,在真正开始之前还需要经过一些判断,比如是否已经处理过或者是否需要跳过的bean,而真正创建代理的代码是从getAdvicesAndAdvisorsForBean开始的。

    创建代理主要包含了两个步骤:

      (1)获取增强方法或者增强器;

      (2)根据获取的增强进行代理;

    虽然上述步骤看似简单,但是每个步骤中都经历了大量的复杂的逻辑。首先来看看获取增强方法的实现逻辑:

    protected Object[] getAdvicesAndAdvisorsForBean(
                Class<?> beanClass, String beanName, @Nullable 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;
        }

    对于指定bean的增强方法的获取一定是包含两个步骤的,获取所有的增强以及寻找所有增强中适用于bean的增强并应用,那么findCandidateAdvisors和findAdvisorsThatCanApply便是做这两件事情。当然,如果无法找到对应的增强器便返回DO_NOT_PROXY,其中DO_NOT_PROXY = null。

    获取增强器

    由于我们分析的是使用注解进行的AOP,所以对于findCandidateAdvisors的实现其实是由AnnotationAwareAspectJAutoProxyCreator类完成的,我们继续跟踪AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法:

    protected List<Advisor> findCandidateAdvisors() {
            //当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持,在这里调用父类方法加载配置文件中的AOP声明
            List<Advisor> advisors = super.findCandidateAdvisors();
            //为bean工厂中的所有AspectJ方面构建Advisor
            if (this.aspectJAdvisorsBuilder != null) {
                advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
            }
            return advisors;
        }

     AnnotationAwareAspectJAutoProxyCreator间接的继承了AbstractAdvisorAutoProxyCreator,在实现获取增强的方法中除了保留父类的获取配置文件中定义的增强外,同时添加了获取bean的注解增强的功能,那么其实现正是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来实现的。

    public List<Advisor> buildAspectJAdvisors() {
            List<String> aspectNames = this.aspectBeanNames;
    
            if (aspectNames == null) {
                synchronized (this) {
                    aspectNames = this.aspectBeanNames;
                    if (aspectNames == null) {
                        List<Advisor> advisors = new ArrayList<>();
                        aspectNames = new ArrayList<>();
                        //获取所有的beanName
                        String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                                this.beanFactory, Object.class, true, false);
                        //循环所有beanName找出对应的增强方法
                        for (String beanName : beanNames) {
                            //不合法的bean则略过,由子类定义规则,默认返回true
                            if (!isEligibleBean(beanName)) {
                                continue;
                            }
                            // 获取对应的bean类型
                            Class<?> beanType = this.beanFactory.getType(beanName);
                            if (beanType == null) {
                                continue;
                            }
                            //判断是否存在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);
                                    //解析标记AspectJ注解中的增强方法
                                    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 {
                                    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 ArrayList<>();
            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;
        }
    buildAspectJAdvisors

     至此,我们已经完成了对Advisor的提取,在上面的步骤中最为重要也最为复杂的就是增强器的获取。而这一功能是委托给了getAdvisor方法去实现(this.advisorFactory.getAdvisors(factory))。

    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
            //获取标记为AspectJ的类
            Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
            //获取标记为AspectJ的name
            String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
            //验证
            validate(aspectClass);
    
            // 我们需要用装饰器包装MetadataAwareAspectInstanceFactory这样它只实例化一次。
            MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
                    new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
    
            List<Advisor> advisors = new ArrayList<>();
            for (Method method : getAdvisorMethods(aspectClass)) {
                Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
                if (advisor != null) {
                    advisors.add(advisor);
                }
            }
    
            // 如果寻找的增强器不为空且又配置了增强延迟初始化那么需要在首位加入同步实例化增强器
            if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
                Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
                advisors.add(0, instantiationAdvisor);
            }
    
            // 获取DeclareParents注解
            for (Field field : aspectClass.getDeclaredFields()) {
                Advisor advisor = getDeclareParentsAdvisor(field);
                if (advisor != null) {
                    advisors.add(advisor);
                }
            }
    
            return advisors;
        }

    函数中首先完成了对增强器的获取,包括获取注解以及根据注解生成增强的步骤,然后考虑到在配置中可能会将增强配置成延迟初始化,那么需要在首位加入同步实例化增强器以保证增强使用之前的实例化,最后对DeclareParents注解的获取。接下来详细的介绍每一个步骤。

    1.普通增强器的获取 

     普通增强器的获取是通过getAdvisor方法实现的,实现的步骤包括对切点的注解的获取以及根据注解信息生成增强。

    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);
        }

    (1)切点信息的获取。所谓的切点信息的获取就是指定注解的表达式的信息的获取。如@Before("test()"):

    private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
            //获取方法上的注解
            AspectJAnnotation<?> aspectJAnnotation =
                    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
            if (aspectJAnnotation == null) {
                return null;
            }
            //使用AspectJExpressionPointcut实例封装获取的信息
            AspectJExpressionPointcut ajexp =
                    new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
            ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
            if (this.beanFactory != null) {
                ajexp.setBeanFactory(this.beanFactory);
            }
            return ajexp;
        }
    aspectJAnnotation.getPointcutExpression():提取得到注解中的表达式如:@Pointcut("execute(* *.*test*(...))")中的execute(* *.*test*(...))
    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;
        }
    //获取指定方法上的注解并使用AspectJAnnotation进行封装
        private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
            A result = AnnotationUtils.findAnnotation(method, toLookFor);
            if (result != null) {
                return new AspectJAnnotation<>(result);
            }
            else {
                return null;
            }
        }

     (2)根据切点信息生成增强。所有的增强器都是有Advisor的实现类InstantiationModelAwarePointcutAdvisorImpl统一封装的。

    在封装的过程中只是简单地将信息封装在类的实例中,所有的信息单纯的赋值,在实例初始化的过程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如@Before("test()")和@After("test()")标签的不同就是增强器的位置不同,所以就需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的增强器就是在instantiateAdvice函数中实现的。

      在该函数中,Spring会根据不同的注解来生成不同的增强器。例如:AtBefore会对应AspectJMethodBeforeAdvice,而在AspectJMethodBeforeAdvice中完成了增强方法的逻辑。

    2.增强同步实例化增强器

     如果寻找的增强器不为空而且又配置了增强延迟初始化,那么久需要在首位加入同步实例化增强器。同步实例化增强器SyntheticInstantiationAdvisor如下:

    protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {
    
            public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {
                super(aif.getAspectMetadata().getPerClausePointcut(), (MethodBeforeAdvice)//目标方法前调用,类似于@Before
                        (method, args, target) -> aif.getAspectInstance());
            }
        }
    3.获取DeclareParents注解 

     DeclareParents主要用于引介增强的注解形式的实现,而其实现方式与普通增强很相似,只不过使用DeclareParentsAdvisor对功能进行封装。

    private Advisor getDeclareParentsAdvisor(Field introductionField) {
            DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
            if (declareParents == null) {
                // Not an introduction field
                return null;
            }
    
            if (DeclareParents.class == declareParents.defaultImpl()) {
                throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
            }
    
            return new DeclareParentsAdvisor(
                    introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
        }

    至此,已经将 创建代理AOP的第一步:获取增强方法或者增强器讲述完毕了。接下来是第二步:寻找匹配的增强器

    寻找匹配的增强器

    前面的函数已经完成了所有增强器的解析,但是对于所有的增强器来讲,并不一定都适用于当前的bean,还要挑选取出适合的增强器,也就是满足我们配置的通配符的增强器,具体的实现在findAdvisorsThatCanApply中。

    protected List<Advisor> findAdvisorsThatCanApply(
                List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    
            ProxyCreationContext.setCurrentProxiedBeanName(beanName);
            try {
                //过滤已经得到的Advisors
                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 ArrayList<>();
            //首先处理引介增强
            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;
        }

    findAdvisorsThatCanApply函数的主要功能是寻找所有增强器中适用于当前class的增强器。引介增强与普通的增强的处理是不一样的,所以分开来处理。而对于真正的匹配在canApply中实现。

    参考:《Spring源码深度解析》 郝佳 编著:

    作者:Joe
    努力了的才叫梦想,不努力的就是空想,努力并且坚持下去,毕竟这是我相信的力量
  • 相关阅读:
    问题 A: 【递归入门】全排列
    第一个struct2程序(2)
    第一个struct2程序
    Java学习 第二节
    重学Java
    Servlet过滤器
    struct2
    Java web struct入门基础知识
    one by one 项目 part 6
    软件工程导论 桩模块和驱动模块
  • 原文地址:https://www.cnblogs.com/Joe-Go/p/10233694.html
Copyright © 2020-2023  润新知