美文网首页
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