AOP源码解析(三)增强器的获取

来源:互联网 发布:cc域名注册哪里便宜 编辑:程序博客网 时间:2024/06/07 00:55

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

    public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName)    {        validate(aif.getAspectMetadata().getAspectClass());        //切点信息的获取        AspectJExpressionPointcut ajexp = getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());        if(ajexp == null)            return null;        else            //根据切点信息生成增强器            return new InstantiationModelAwarePointcutAdvisorImpl(this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);    }

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

    private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class candidateAspectClass)    {        //获取方法上的注解        AbstractAspectJAdvisorFactory.AspectJAnnotation aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);        if(aspectJAnnotation == null)        {            return null;        } else        {            //使用AspectJExpressionPointcut实例封装获取的信息            AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);            //提取得到的注解中的表达式如:@Pointcut("execution(* *.*test*(..))")中的execution(* *.*test*(..))<pre name="code" class="java">   

))
ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); return ajexp; } }


 protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method)    {        //设置敏感的注解类        Class classesToLookFor[] = {            org/aspectj/lang/annotation/Before, org/aspectj/lang/annotation/Around, org/aspectj/lang/annotation/After, org/aspectj/lang/annotation/AfterReturning, org/aspectj/lang/annotation/AfterThrowing, org/aspectj/lang/annotation/Pointcut        };        for(Class<? extends Annotation> c : classsesToLookFor)        {            AspectJAnnotation foundAnnotation = findAnnotation(method, c);            if(foundAnnotation != null)                return foundAnnotation;        }        return null;    }
//获取指定方法上的注解并使用AspectJAnnotation封装
    private static AspectJAnnotation findAnnotation(Method method, Class toLookFor)    {        Annotation result = AnnotationUtils.findAnnotation(method, toLookFor);        if(result != null)            return new AspectJAnnotation(result);        else            return null;    }
(2)根据切点信息生成增强。所有的增强都有Advisor实现类InstantiationModelAwarePontcutAdvisorImpl统一疯长。
    public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName)    {        declaredPointcut = ajexp;        this.method = method;        atAspectJAdvisorFactory = af;        aspectInstanceFactory = aif;        declarationOrder = declarationOrderInAspect;        this.aspectName = aspectName;        if(aif.getAspectMetadata().isLazilyInstantiated())        {            Pointcut preInstantiationPointcut = Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), declaredPointcut);            pointcut = new PerTargetInstantiationModelPointcut(declaredPointcut, preInstantiationPointcut, aif);            lazy = true;        } else        {            instantiatedAdvice = instantiateAdvice(declaredPointcut);            pointcut = declaredPointcut;            lazy = false;        }    }

封装过程只是简单地将信息封装在类的实例中,所有的额信息单纯地复制。在实例初始化的过程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如@Before(“test()”)与After(“test()”)标签的不同就是增强器增强的位置不同,所以就需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的额增强器就是在instantiateAdvice函数中实现的。
    private Advice instantiateAdvice(AspectJExpressionPointcut pcut)    {        return atAspectJAdvisorFactory.getAdvice(method, pcut, aspectInstanceFactory, declarationOrder, aspectName);    }

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName)    {        Class candidateAspectClass = aif.getAspectMetadata().getAspectClass();        validate(candidateAspectClass);        AbstractAspectJAdvisorFactory.AspectJAnnotation aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);        if(aspectJAnnotation == null)            return null;       //if we get here,we know we have an AspectJ method. Check that its an AspectJ-annotated class        if(!isAspect(candidateAspectClass))            throw new AopConfigException((new StringBuilder()).append("Advice must be declared inside an aspect type: Offending method '").append(candidateAdviceMethod).append("' in class [").append(candidateAspectClass.getName()).append("]").toString());        if(logger.isDebugEnabled())            logger.debug((new StringBuilder()).append("Found AspectJ method: ").append(candidateAdviceMethod).toString());        AbstractAspectJAdvice springAdvice;        switch(_cls4..SwitchMap.org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotationType[aspectJAnnotation.getAnnotationType().ordinal()])        {        case 1: // '\001'            springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);            break;        case 2: // '\002'            springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);            break;        case 3: // '\003'            springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);            AfterReturning afterReturningAnnotation = (AfterReturning)aspectJAnnotation.getAnnotation();            if(StringUtils.hasText(afterReturningAnnotation.returning()))                springAdvice.setReturningName(afterReturningAnnotation.returning());            break;        case 4: // '\004'            springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);            AfterThrowing afterThrowingAnnotation = (AfterThrowing)aspectJAnnotation.getAnnotation();            if(StringUtils.hasText(afterThrowingAnnotation.throwing()))                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());            break;        case 5: // '\005'            springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);            break;        case 6: // '\006'            if(logger.isDebugEnabled())                logger.debug((new StringBuilder()).append("Processing pointcut '").append(candidateAdviceMethod.getName()).append("'").toString());            return null;        default:            throw new UnsupportedOperationException((new StringBuilder()).append("Unsupported advice type on method ").append(candidateAdviceMethod).toString());        }        springAdvice.setAspectName(aspectName);        springAdvice.setDeclarationOrder(declarationOrderInAspect);        String argNames[] = parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);        if(argNames != null)            springAdvice.setArgumentNamesFromStringArray(argNames);        springAdvice.calculateArgumentBindings();        return springAdvice;    }        }
从函数中可以看到,Spring会根据不同的注解生成不同的增强器,例如AtBefore会对应AspectJMethodBeforeAdvice。

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

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

 protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor    {        public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif)        {            super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() {                //目前方法前调用,类似@Before                public void before(Method method, Object args[], Object target)                {   //简单初始化aspect                    aif.getAspectInstance();                }

3.获取DeclareParents注解


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

    private Advisor getDeclareParentsAdvisor(Field introductionField)    {        DeclareParents declareParents = (DeclareParents)introductionField.getAnnotation(org/aspectj/lang/annotation/DeclareParents);        if(declareParents == null)            return null;        if(org/aspectj/lang/annotation/DeclareParents.equals(declareParents.defaultImpl()))            throw new IllegalStateException("defaultImpl must be set on DeclareParents");        else            return new DeclareParentsAdvisor(introductionField.getType(), declareParents.value(), declareParents.defaultImpl());    }
后面一节我们一起分析一下,Spring如何寻找匹配的增强器,篇幅较长,也比较复杂,但还是希望我们一起看下去,因为这个过程虽然很艰辛,坚持过后,你会发现,收获是非常巨大的。


0 0
原创粉丝点击