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

普通增强器的获取逻辑通过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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOPSpring框架中的一个重要模块,它提供了一种面向切面编程的方式,可以让开发者将一些通用的、横切的关注点(如事务、安全、缓存等)从业务逻辑中剥离出来,使得业务逻辑更加清晰简洁,代码复用更加方便。 Spring AOP的实现原理主要基于Java动态代理和CGLIB动态代理两种方式,其中Java动态代理主要用于接口代理,而CGLIB动态代理则主要用于类代理。Spring AOP中的核心概念是切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)和织入(Weaving)。 在Spring AOP中,切面是一个横向的关注点,它跨越多个对象和方法,通常包含一些通用的功能,如日志记录、安全控制等。连接点则是程序中可以被切面拦截的特定点,如方法调用、异常抛出等。通知是切面在连接点执行前后所执行的动作,包括前置通知(Before)、后置通知(After)、异常通知(AfterThrowing)、返回通知(AfterReturning)和环绕通知(Around)。切点则是用来匹配连接点的规则,它可以指定哪些连接点会被切面拦截。织入则是将切面应用到目标对象中的过程,它可以在编译时、类加载时、运行时等不同的阶段进行。 Spring AOP源码解析涉及到很多细节,包括代理的生成、通知的执行、切点的匹配等,需要深入了解Spring框架的内部实现和Java的反射机制。对于初学者而言,可以先从Spring AOP的基本概念和用法入手,了解其实现原理的同时,也可以通过调试和查看源码来加深理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值