Spring aop(3)2018-08-14

接着上一节Spring aop(2):
2.3: this.addAdvisorsFromAspectInstanceFactory获取advisor:
a、我们先来看下advisor的接口定义:

public interface Advisor {
    Advice EMPTY_ADVICE = new Advice() {
    };

    Advice getAdvice();

    boolean isPerInstance();
}

从接口定义可以看出:advisor就是组合了Advice

b、addAdvisorsFromAspectInstanceFactory的代码:

private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();

private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) {
        //获取Advisors集合
        List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory);
        //从中挑出适用于目标对象的Advisor
        advisors = AopUtils.findAdvisorsThatCanApply(advisors, getTargetClass());
        AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
        //对获取到的Advisor进行排序
        AnnotationAwareOrderComparator.sort(advisors);
        //将获取到Advisor添加到advisors集合中
        addAdvisors(advisors);
    }

从代码中我们可以看出:addAdvisorsFromAspectInstanceFactory先从ReflectiveAspectJAdvisorFactory中的getAdvisor从MetadataAwareAspectInstanceFactory中获取advisors。然后根据目标类进行过滤、排序,最后添加到advisors集合中。

c、我们接着看getAdvisors方法:

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实例又包装为LazySingletonAspectInstanceFactoryDecorator
        MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
                new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

        List<Advisor> advisors = new LinkedList<>();
         //调用getAdvisorMethods方法来获取切面类中所有不包含Pointcut注解的方法。
        for (Method method : getAdvisorMethods(aspectClass)) {
             //得到Advisor
            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;
    }

d、这边我们看下是validate(aspectClass)是什么校验的:

//校验我们的切面类是否带有Aspect注解
 public void validate(Class<?> aspectClass) throws AopConfigException {
        //如果我们的带有@Aspect注解的类的父类也带有@Aspect注解并且其还不是抽象类 则抛出异常
        if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null &&
                !Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) {
            throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" +
                    aspectClass.getSuperclass().getName() + "]");
        }
        AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
        //再次校验 切面类是否带有 @Aspect注解
        if (!ajType.isAspect()) {
            throw new NotAnAtAspectException(aspectClass);
        }
        //下面这两个一般遇不到
        if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {
            throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " +
                    "This is not supported in Spring AOP.");
        }
        if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {
            throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " +
                    "This is not supported in Spring AOP.");
        }
    }

e、接着我们getAdvisorMethods(aspectClass)方法:

private List<Method> getAdvisorMethods(Class<?> aspectClass) {
        final List<Method> methods = new LinkedList<Method>();
 
        ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
            //ReflectionUtils.MethodCallback的匿名实现
            @Override
            public void doWith(Method method) throws IllegalArgumentException {
                // Exclude pointcuts
                //不带Pointcut注解的方法 添加到methods集合中
                if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                    methods.add(method);
                }
            }
        });
        Collections.sort(methods, METHOD_COMPARATOR);
        return methods;
    }

f、接着我们看下getAdvisor方法:

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {
        //验证切面类
        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
        //这里根据传入的方法和切面类获取 切点表达式
        AspectJExpressionPointcut expressionPointcut = getPointcut(
                candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        //没有获取到切点表达式 直接返回null
        if (expressionPointcut == null) {
            return null;
        }
        //返回一个Advisor的实例 这个实例中包含了 一下内容
        //(1、切点表达式 AspectJExpressionPointcut 
        //2、切点方法 
        //3、ReflectiveAspectJAdvisorFactory工厂实例
        //4、切面类实例
        //5、切面类名字
        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    }

j、getAdvisor 中的getPointcut获取切点表达式方法:

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
        //查找方法上存在切面注解(通知类型注解) 即方法上是否有
        //@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut注解并返回AspectJAnnotation的类型
        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());
        ajexp.setBeanFactory(this.beanFactory);
        return ajexp;
    }

     @Nullable
    protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
        Class<?>[] classesToLookFor = new Class<?>[] {
                Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
        for (Class<?> c : classesToLookFor) {
            AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
            if (foundAnnotation != null) {
                return foundAnnotation;
            }
        }
        return null;
    }

g、接着我们看下getAdvisor方法中的InstantiationModelAwarePointcutAdvisorImpl对象的构造方法:

 public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
            Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
            MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
        //切点表达式类 AspectJExpressionPointcut 
        this.declaredPointcut = declaredPointcut;
        //切面类 
        this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
        //切点表达式方法所在的方法名 这里指的是@Before、@After这些通知类型所在的方法名
        this.methodName = aspectJAdviceMethod.getName();
        //通知参数类型
        this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
        //切面通知方法
        this.aspectJAdviceMethod = aspectJAdviceMethod;
        //ReflectiveAspectJAdvisorFactory实例
        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);
            this.pointcut = new PerTargetInstantiationModelPointcut(
                    this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
            this.lazy = true;
        }
        else {
            // A singleton aspect.
            //切点表达式类
            this.pointcut = this.declaredPointcut;
            this.lazy = false;
            //这里获取Advice实例 
            this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
        }
    }

l、接着我们看下InstantiationModelAwarePointcutAdvisorImpl构造方法中的
instantiateAdvice(this.declaredPointcut)方法:

private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
    //入参为:通知方法、切点表达式类、切面实例、切面的一个顺序、切面类名
    return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
            this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    }


public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
            MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
        //切面类 带有@Aspect注解的类
        Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        //验证切面类
        validate(candidateAspectClass);
        //根据通知方法 获取通知注解相关信息
        AspectJAnnotation<?> aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
            return null;
        }
        //校验不是切面类则抛出异常
        if (!isAspect(candidateAspectClass)) {
            throw new AopConfigException("Advice must be declared inside an aspect type: " +
                    "Offending method '" + candidateAdviceMethod + "' in class [" +
                    candidateAspectClass.getName() + "]");
        }
        AbstractAspectJAdvice springAdvice;
        //获取通知类型
        switch (aspectJAnnotation.getAnnotationType()) {
            //如果是前置通知,则直接创建AspectJMethodBeforeAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtBefore:
                springAdvice = new AspectJMethodBeforeAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            //如果是后置通知,则直接创建AspectJAfterAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtAfter:
                springAdvice = new AspectJAfterAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            //如果是后置返回通知,则直接创建AspectJAfterReturningAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtAfterReturning:
                springAdvice = new AspectJAfterReturningAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                //设置后置返回值的参数name
                if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                    springAdvice.setReturningName(afterReturningAnnotation.returning());
                }
                break;
            //如果是后置异常通知,则直接创建AspectJAfterThrowingAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtAfterThrowing:
                springAdvice = new AspectJAfterThrowingAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                //设置后置异常通知 异常类型参数name
                if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                    springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                }
                break;
            //如果是后置异常通知,则直接创建AspectJAfterThrowingAdvice实例
            //入参为:通知方法、切点表达式、切面实例
            case AtAround:
                springAdvice = new AspectJAroundAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            //如果是切点方法,则什么也不做
            case AtPointcut:
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                }
                return null;
            //上面的那几种情况都不是的话,则抛出异常
            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;
    }

今天先到这里。。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容

  • 源码: # 前言 前两篇文章我们分析了AOP的原理,知道了AOP的核心就是代理,通知器,切点。我们也知道了XML配...
    莫那一鲁道阅读 2,632评论 0 6
  • 导读 本篇主要针对spring aop进行源码级解说,如有不不到位的地方敬请指出,多谢…… 本文大纲如下 spri...
    青芒v5阅读 1,644评论 0 13
  • 拖了一年多,今日才解决好的事情 总结: 处理一些问题时,需要了解对方的性格特征! 别人的建议只能做为参考,因为只有...
    Mary妹善阅读 155评论 0 0
  • 都说字如其人,写一手漂亮的好字是我从小就梦想的。人生第一次开始想好好写字是在11那年,我的同桌,一个漂亮乖巧的女...
    墨水深蓝阅读 186评论 0 0
  • 我喜欢穿棉麻的衣服 因为它的质地 有时光磋磨而出的坚韧 以及你与生俱来的温柔 在还拙稚的年岁里 我喜欢幽谷溪涧边丛...
    有女褰裳阅读 182评论 0 0