AOP动态代理解析3-增强方法的获取

简介: 对于指定bean的增强方法的获取一定是包含两个步骤的: 获取所有的增强 寻找所有增强中使用于bean的增强并应用 那么findCandidateAdvisors与findAdvisorsThatCanApply便是做了这两件事情。

对于指定bean的增强方法的获取一定是包含两个步骤的:

  1. 获取所有的增强
  2. 寻找所有增强中使用于bean的增强并应用

那么findCandidateAdvisors与findAdvisorsThatCanApply便是做了这两件事情。当然,如果无法找到对应的增强器便返回DO_NOT_PROXY,其中DO_NOT_PROXY=null.

protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource)  
{  
    List advisors = findEligibleAdvisors(beanClass, beanName);  
    if(advisors.isEmpty())  
        return DO_NOT_PROXY;  
    else  
        return advisors.toArray();  
}  
protected List findEligibleAdvisors(Class beanClass, String beanName)  
{  
  //获取所有的增强器 List candidateAdvisors
= findCandidateAdvisors();
  //获取适合beanname的增强器 List eligibleAdvisors
= findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if(!eligibleAdvisors.isEmpty()) eligibleAdvisors = sortAdvisors(eligibleAdvisors); return eligibleAdvisors; }

所有增强器的获取

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

protected List findCandidateAdvisors()  
{  
    //当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持。  
    //在这里调用父类方法加载配置文件中的AOP声明  
    List advisors = super.findCandidateAdvisors();  
    //Build Advisors for all AspectJ aspects in the bean factory  
    advisors.addAll(aspectJAdvisorsBuilder.buildAspectJAdvisors());  
    return advisors;  
}

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

(1)获取所有beanName,这一步骤中所有在beanFactory中注册的Bean都会被提取出来。

(2)遍历所有beanName,并找出声明AspectJ注解的类,进行进一步的处理。

(3)对标记为AspectJ注解的类进行增强器的提取。

(4)将提取结果加入缓存。

提取Advisor

现在来看看函数实现,对Spirng中所有的类进行分析,提取Advisor。

public List buildAspectJAdvisors()  
    {  
        List aspectNames = null;  
        synchronized(this){  
        aspectNames = aspectBeanNames;  
        if(aspectNames == null)  
        {  
            List advisors = new LinkedList();  
            aspectNames = new LinkedList();  
            //获取所有的beanName  
            String beanNames[] = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, java/lang/Object, true, false);  
            //循环所有的beanName找出对应的增强方法  
            for(String beanName : beanNames)  
            {  
                //不合法的bean则略过,由子类定义规则,默认返回true  
               if(!isEligibleBean(beanName))  
                    continue;  
                //获取对应的bean的类型  
                Class beanType = beanFactory.getType(beanName);  
                //如果存在Aspect注解  
               if(beanType == null || !advisorFactory.isAspect(beanType))  
                    continue;  
                aspectNames.add(beanName);  
                AspectMetadata amd = new AspectMetadata(beanType, beanName);  
                MetadataAwareAspectInstanceFactory factory;  
                if(amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON)  
                {  
                    factory = new BeanFactoryAspectInstanceFactory(beanFactory, beanName);  
                    //解析标记AspectJ注解中的增强方法  
                    List classAdvisors = advisorFactory.getAdvisors(factory);  
                    if(beanFactory.isSingleton(beanName))  
                        advisorsCache.put(beanName, classAdvisors);  
                    else  
                        aspectFactoryCache.put(beanName, factory);  
                    advisors.addAll(classAdvisors);  
                    continue;  
                }  
                if(beanFactory.isSingleton(beanName))  
                    throw new IllegalArgumentException((
                    new StringBuilder()).append("Bean with name '")
                                .append(beanName)
                                .append("' is a singleton, but aspect instantiation model is not singleton")
                                .toString()); factory
= new PrototypeAspectInstanceFactory(beanFactory, beanName); aspectFactoryCache.put(beanName, factory); advisors.addAll(advisorFactory.getAdvisors(factory)); } aspectBeanNames = aspectNames; return advisors; }

至此,已经完成了Advisor的提取。

切点信息的获取

在上面的步骤中最为重要也最为繁杂的就是增强器的获取,而这一切功能委托给了getAdvisors方法去实现(this.advisorFactory.getAdvisors(factory))。

    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
     //获取标记为AspectJ的类 
        final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
     //获取标记为AspectJ的name
        final String aspectName = maaif.getAspectMetadata().getAspectName();
     //验证
        validate(aspectClass);
        final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
                new LazySingletonAspectInstanceFactoryDecorator(maaif);
        final List<Advisor> advisors = new LinkedList<Advisor>();
        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注解的获取。

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

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

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

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]);
    //提取得到的注解中的表达式如:@Pointcut("execution(* *.*test*(..))")中的execution(* *.*test*(..))
    ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
    return ajexp;
}

protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {
    //设置敏感的注解类
    Class<? extends Annotation>[] classesToLookFor = new Class[] {
            Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
    for (Class<? extends Annotation> c : classesToLookFor) {
        AspectJAnnotation foundAnnotation = findAnnotation(method, c);
        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<A>(result);
    }
    else {
        return null;
    }
}

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

public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
        MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {

    this.declaredPointcut = ajexp;
    this.method = method;
    this.atAspectJAdvisorFactory = af;
    this.aspectInstanceFactory = aif;
    this.declarationOrder = declarationOrderInAspect;
    this.aspectName = aspectName;

    if (aif.getAspectMetadata().isLazilyInstantiated()) {
        Pointcut preInstantiationPointcut =
                Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
        this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif);
        this.lazy = true;
    }
    else {
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
        this.pointcut = declaredPointcut;
        this.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(!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(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。

增加同步实例化增强器

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

    protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {
        public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {
            super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() {
                @Override
                public void before(Method method, Object[] args, Object target) {
                    // Simply instantiate the aspect
                    aif.getAspectInstance();
                }
            });
        }
    }

获取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());  
}  

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

获取合适的增强器

findAdvisorsThatCanApply函数的主要功能是寻找所有增强器中适用于当前class的增强器。对于真是的匹配在canApply中实现。

protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        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 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) {
            continue;
        }
        //对于普通bean的处理  
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}
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();
    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 = clazz.getMethods();
        for (Method method : methods) {
            if ((introductionAwareMethodMatcher != null &&
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }
    return false;
}

 

 

 

 

 

 

 

 

 

目录
相关文章
|
29天前
|
机器学习/深度学习 存储 PyTorch
Pytorch中in-place操作相关错误解析及detach()方法说明
Pytorch中in-place操作相关错误解析及detach()方法说明
41 0
|
1月前
|
存储 开发框架 开发者
QT C++焦点事件:多角度解析实用技巧与方法
QT C++焦点事件:多角度解析实用技巧与方法
143 0
|
1月前
|
敏捷开发 开发框架 数据可视化
|
1月前
|
监控 Java 开发者
Spring AOP动态代理
Spring AOP动态代理
43 1
|
1月前
|
C语言
【C语言】大小写字母的相互转化:多种方法解析及原理说明
【C语言】大小写字母的相互转化:多种方法解析及原理说明
104 0
|
1月前
|
机器学习/深度学习 数据采集 自然语言处理
岭回归与LASSO回归:解析两大经典线性回归方法
岭回归与LASSO回归:解析两大经典线性回归方法
岭回归与LASSO回归:解析两大经典线性回归方法
|
1天前
|
SQL 分布式计算 资源调度
一文解析 ODPS SQL 任务优化方法原理
本文重点尝试从ODPS SQL的逻辑执行计划和Logview中的执行计划出发,分析日常数据研发过程中各种优化方法背后的原理,覆盖了部分调优方法的分析,从知道怎么优化,到为什么这样优化,以及还能怎样优化。
|
1天前
并发编程之Callable方法的详细解析(带小案例)
并发编程之Callable方法的详细解析(带小案例)
4 0
|
1天前
|
Java 数据库
Javaweb之SpringBootWeb案例之AOP案例的详细解析
Javaweb之SpringBootWeb案例之AOP案例的详细解析
3 0
|
11天前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
25 0
切面编程的艺术:Spring动态代理解析与实战

推荐镜像

更多