美文网首页
Spring AOP 源码读后记录

Spring AOP 源码读后记录

作者: 柚子过来 | 来源:发表于2018-03-07 14:05 被阅读0次

    aop可以用来在不修改原代码的情况下为原代码 添加增强功能,先写一个使用的小例子:

    我们先定义一个功能代码:

    @Component
    public class Client {
    public void print(){
        System.out.println("client print");
    }
    }
    

    现在需要切入aop增强其功能,所要做的只有一件事:定义增强切面(其中包括切点以及通知):

    @Aspect
    @Component
    public class Jaop {
    @Pointcut("execution(* Client.*(..))")  //定义切点,execution指定需要切入的地方,这里指Client类的所有方法
    public void print(){}                   //或者这样指定太麻烦,也可以自定义一个注解,然后将execution的值指定为该注解,这样使用了该注解的方法都会被增强功能
    
    @Before("print()")
    public void beforePrint() {
        System.out.println("before print");
    }
    
    @After("print()")
    public void afterPrint() {
        System.out.println("after print");
    }
    
    @Around("print()")
    public void around(ProceedingJoinPoint p) throws Throwable {
        System.out.println("around before");
        p.proceed();
        System.out.println("around after");
    }
    }
    

    其实这样就可以了,如果调用Client的print方法时会触发aop的增强功能。

    那aop的原理是什么呢?其实就是动态代理,当然动态代理包括JDK动态代理和cglib动态代理,下面介绍下源码解析:

    aop的最开始在于AnnotationAwareAspectJAutoProxyCreator类(自动代理创建器),查看它的类结构图可以发现它实现了BeanPostProcessor接口,那么一切就清楚了,应该是所有的Bean实例化前后会执行这个Bean后处理器来创建代理(给实例对象创建代理对象来增强功能的原理就不说了)。下面来看看是不是这样。

    图片.png

    开启AOP后,Spring会对AnnotationAwareAspectJAutoProxyCreator进行自动注册:

    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }
    

    那么这个AnnotationAwareAspectJAutoProxyCreator做了哪些事呢?
    我们先看看它的顶层接口BeanPostProcessor的定义:

    public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    }
    

    BeanPostProcessor接口提供了两个方法,从命名可以看出来一个是在Bean实例化之前执行,一个是在Bean实例化之后执行。
    而前面类结构图中的AbstractAutoProxyCreator中就重写了postProcessBeforeInitialization方法(重点):

        @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(beanClass, beanName);
    
        if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }
    
        // Create proxy here if we have a custom TargetSource.
        // Suppresses unnecessary default instantiation of the target bean:
        // The TargetSource will handle target instances in a custom fashion.
        if (beanName != null) {
            TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
            if (targetSource != null) {
                this.targetSourcedBeans.add(beanName);
                Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);   *******************
                Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);  //这里就创建了目标Bean的代理对象!!!!!!!!
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            }
        }
    
        return null;
    }
    
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) {
        return true;
    }
    

    postProcessBeforeInitialization方法中的判断条件什么的就不说了,主要是getAdvicesAndAdvisorsForBean与createProxy那两句,这两句就获取了所有可以应用到该Bean上的增强方法并创建了代理对象。先看getAdvicesAndAdvisorsForBean方法:

    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, 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上的增强方法
    }
    

    上面的findCandidateAdvisors就是获取了所有的增强方法,它的具体做法大概分几步:1、获取所有Aspect注解的增强类的beanName(直接获取beanDefinitionNames集合进行条件过滤就行)。2、再通过beanName获得所有对应的Advisor增强对象。

    获取了所有的增强对象后,就需要再过滤一遍看看哪些可以应用在当前的Bean上,那就是findAdvisorsThatCanApply做的事了,这个方法里面最主要的就是canApply方法:

     //可以看出就是看Advisor的增强条件是不是和该Bean的方法匹配
    public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
        if (advisor instanceof IntroductionAdvisor) {
            return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
        }
        else if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pca = (PointcutAdvisor) advisor;
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
        else {
            // It doesn't have a pointcut so we assume it applies.
            return true;
        }
    }
    

    至此,前面的代码先是在Bean实例化前进入了Bean后处理器,然后获取了所有符合条件可以应用在该Bean的Advisor。那后面顺理成章创建动态代理将增强功能织入就OK了,继续。

    下面就看看怎么创建Proxy的
    从postProcessBeforeInitialization的createProxy进去是这个样子:

    protected Object createProxy(
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
        ... ...
    
        ProxyFactory proxyFactory = new ProxyFactory();
    
        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);     **********
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }
    
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        for (Advisor advisor : advisors) {
            proxyFactory.addAdvisor(advisor);            **********
        }
    
        proxyFactory.setTargetSource(targetSource);         **********
    
        return proxyFactory.getProxy(getProxyClassLoader());  **********
    }
    

    最后可以看出,生成代理对象由proxyFactory完成,只需要将类加载器、接口等参数传给它就行了。
    不对,好像少了什么....JDK的动态代理需要Handler啊,这里需要把Advisor对象转换成Handler吧,找找在哪.....

    public Object getProxy(ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
    }
    
    @Override
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 
    }
    

    上面最后一句显示Handler的参数是this,说明是createAopProxy()返回的啊,进去看看,果然:

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
                        ... ...
            return new JdkDynamicAopProxy(config);
    }
    
    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
      ... ...
    }
    

    好了,AOP的源码分析基本结束了,总结一下过程:

    1、注册一个Bean后处理器并重写了postProcessBeforeInitialization方法来对Bean实例化前做操作,在处理器中进行后几步的操作:
    2、获取beanFactory中注册的所有Advisor(即@Aspect注解的)的beanName,并获取对象。
    3、过滤出可以应用在当前bean上的所有Advisor。
    4、创建ProxyFactory,并将classLoader、interface等参数传递给它
    5、以Advisor为参数创建InvocationHandler
    6、Proxy.newProxyInstance。三个参数都有了(classLoader、interface、Handler)

    相关文章

      网友评论

          本文标题:Spring AOP 源码读后记录

          本文链接:https://www.haomeiwen.com/subject/raihfftx.html