• 1

  • 1

[Spring 系列] AOP 源码解析

1星期前

前言

前言的仪式感还是要有的。这次回来讲 Spring AOP 的主要原因之前写过一篇文章是关于 AOP 的一个概念性文章,然后作死地在文末讲“下一篇会进行源码”解析。但是后面却跑去写别的知识了。额...

其实造成我这么偏执写 Spring AOP 的原因是,毕竟是框架重点,里面的抽象代码以及思想不能丢;况且,咱们淳朴的程序猿,如果不能实打实地看到代码实现,怎么可能善罢甘休!

这篇文章主要还是希望能够完完整整地讲明白 AOP In Spring 是怎么实现的。所以整篇文章的顺序是:

  1. AOP 的实现原理
  2. AOP 的具体源码解析
  3. 手写一个简易版的 AOP 来加深理解

Let' Go!

实现原理

关于原理,上篇文章 Spring AOP 之详解与基础用法② 我有说过一点点。但是目前还是想补充一下。

Spring AOP 的实现方式有两种:AspectJ 与 Spring AOP。它们的区别在于

Spring AOP AspectJ
只在 Java 实现 使用 Java 编程语言的扩展实现
不需要单独的编译过程 使用 AspectJ 特定编译器,除非 LTW 被设置
只有运行时编织可用 运行时织入不可用。支持编译时,编译后和加载时织入
方法级别织入 更加强大 - 包括字段,方法,构造函数,静态初始化器 final 类 / 方法等
依赖 IOC 容器上管理实现 可以应用所有对象
仅支持方法执行切入点 所有方法切面
代理由目标对象创建,并且这些代理应用切面 在代码层面扩展,也就是在 runtime 前生成了代理类
比 AspectJ 慢得多 更高的性能
易学易用 比较复杂

源码解析

版本

此次源码解析是基于 Spring.5.1.2.release 版本上。

解析

我们都知道,Spring 的核心要素是 IOC。所以它预留了非常多的扩展抽象类以及接口。我们就拿一个常规的 SpringBean 管理的生命周期的流程图:

Spring 生命周期

我们可以发现只要实现上面的抽象类的方法,我们就可以通过通过方法在 Bean 的不同阶段的周期对 Bean 进行灵活配置和改变。

那么这个生命周期对于 AOP 起到什么帮助呢?其实不难想象,因为 AOP 的实现原理其实就是动态代理,而我们需要对 Bean 进行代理的话,最好的时间点就是在 Bean 合适的生命周期对其作出改变,这么一想是不是很合理?那我们在这里简单梳理一下,Spring 启动的时候是怎么触发到 AOP 相关的处理器的,步骤如下:

  1. SpringApplication.run() 进行应用启动
  2. run 方法中会调用方法 refreshContext() 进行上下文的准备以及数据刷新
  3. refreshContext 会调用上下问 Context 的 refresh 方法
  4. refresh 里面做很多工作,但是我们只需要关注 finishBeanFactoryInitialization() 方法。
  5. finishBeanFactoryInitialization 会调用 preInstantiateSingletons 方法
  6. preInstantiateSingletons 方法会调用 AbstractBeanFactorygetBean 方法
  7. getBean 继续调用 AbstractBeanFactorydoGetBean 方法
  8. doGetbean 会继续调用 AbstractBeanFactorygetSingleton -> getObject -> doGetBean,最后进入 lambda 循环
  9. 循环的过程中,调用了 AbstractAutowireCapableBeanFactory#createBean 方法。
  10. createBean 这个时候会调用 resolveBeforeInstantiation 方法。这个方法在此时此刻会给 BeanPostProcessors 一个机会去生成代理类来替代原来的目标类,具体会调用的方法就是 postProcessBeforeInstantiationpostProcessAfterInitialization
  11. applyBeanPostProcessorsBeforeInstantiation 方法会通过获取当前上下文的所有 BeanPostProcessors 进行循环,然后调用其 postProcessBeforeInstantiationpostProcessAfterInitialization

ok!虽然中间我们省略过程,但是我们目前来到了比较重要的一步。这个时候,真正去扫描生成 Bean 的时候到了。这个 BeanPostProcessors 中有一个叫 AnnotationAwareAspectJAutoProxyCreator 的类。它实现了 InstantiationAwareBeanPostProcessor(属于 BeanPostProcessor 的子类,主要的功能是在实例化后属性被设置之前会进行自动装配)。同时 AnnotationAwareAspectJAutoProxyCreator 也实例化了 AbstractAutoProxyCreator(属于 BeanPostProcessor 可以拓展 AOP 代理的抽象类)。我们来看看它的 postProcessBeforeInstantiation 方法

需要注意一点,由于 Spring Boot 加载上下文的原因,所以出现加载的类与源码解析不相符,那么有可能是处于不同的上下文当中

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    //获取该 bean 已经缓存好的名字
    Object cacheKey = getCacheKey(beanClass, beanName);
    //根据名判断是否已经加载过了
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        //查看是否是关于 AOP 相关的类 || 判断是否需要跳过加载
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // 获取 TargetSource 
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}
复制代码

上面的代码的步骤是

  1. 通过 isInfrastructureClass 判断是不是 AOP 相关的类
  2. 通过 shouldSkip 来判断是否跳过这个 Bean 的代理
  3. 如果上面都通过了,那么通过 getAdvicesAndAdvisorsForBean 方法获取对应的切面信息
  4. 根据切面信息生成代理类,然后将代理类返回去,便于替换原来的对象类

补充一下,上面的代码中的 TargetSource 其实就是一个持有对象的 Holder。这样的好处在于,真正代理的不是实际对象而是 TargetSource,这样我们可以通过替换 TargetSource 的持有的对象从而实现不用重新生成代理带来的消耗。

那么我们先看一下 shouldSkip 方法是怎么判断需不需要生成代理类的;然后看 getAdvicesAndAdvisorsForBean 是怎么解析找到对应的切面信息的;最后看 createProxySpring 中是怎么生成代理类的。

shouldSkip

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor) {
            if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
                return true;
            }
        }
    }
    return super.shouldSkip(beanClass, beanName);
}
复制代码

上面代码主要是通过 findCandidateAdvisors 方法来获取所有的切面的名字,循环比较是否相同;如果相同则返回 true。而 findCandidateAdvisors 方法主要是调 BeanFactoryAdvisorRetrievalHelper 的方法。需要注意当前类是全局单例,它的作用主要是在当前的 beanFactory 找所有合适的 Advisor,但是不包括 FactoryBeans

public List<Advisor> findAdvisorBeans() {
    //存储 advisors 的名字
    String[] advisorNames = null;
    synchronized (this) {
        advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            // 在这里不会进行 FactoryBeans 的初始化,只要正常的,非加载的类
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Advisor.class, true, false);
            this.cachedAdvisorBeanNames = advisorNames;
        }
    }
    if (advisorNames.length == 0) {
        return new LinkedList<Advisor>();
    }

    List<Advisor> advisors = new LinkedList<Advisor>();
    // 循环 adivors 的名字
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            //如果查看是否排除创建或者是正在创建
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                // log info
            }
            else {
                // 添加
                try {
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    // throw Exception
                }
            }
        }
    }
    return advisors;
}
复制代码

上面主要是从 BeanFactory 中找到 Advisor 的类,然后进行判断。

findCandidateAdvisors() 方法返回的 Bean 可以用缓存来保存,这样有利于提高检索速度

getAdvicesAndAdvisorsForBean

getAdvicesAndAdvisorsForBean 方法在 AbstractAutoProxyCreator 是一个模板方法,主要是预留给子类去实现。我们来看看其子类 AbstractAdvisorAutoProxyCreator 的实现。

	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();
	}
复制代码

findEligibleAdvisors 方法是调用了 AbstractAdvisorAutoProxyCreator 的。

	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;
	}
    
	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
		AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
	}
复制代码

上面代码代码的作用是找到合适 BeanAdvisor。主要是步骤是:

  1. 获取所有的 Advisors
  2. 通过 findAdvisorsThatCanApply 方法将 AdvisorsbeanName 开始匹配
  3. 通过 extendAdvisors 对匹配到的 Advisor 进行一个小扩展(也就是添加一个头 Advisor)
  4. 最后进行排序(便于顺序执行)

下面我将分标题进行讲解!

获取所有 Advisors

我们先看是如何获取所有的 Advisors。这个方法是调用了 AnnotationAwareAspectAutoProxyCreatorfindCandidateAdvisors 方法。

protected List<Advisor> findCandidateAdvisors() {
    // 根据父类规则去获取
    // 其实也就是上面的 advisorRetrievalHelper.findAdvisorBeans() 的调用
    List<Advisor> advisors = super.findCandidateAdvisors();
    // 添加所有带 @Aspect 注解的切面类
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    return advisors;
}
复制代码

通过 findAdvisorsThatCanApply 进行匹配匹配

然后我们看是如何匹配的。

protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    //通过 ThreadLocal 设置 beanName
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}
复制代码

AopUtils.findAdvisorsThatCanApply 进行匹配

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    // 省略一些判断的代码
    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;
        }
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}
复制代码

上面比较核心的代码是 canApply 方法,它主要是用来过滤不合适的 Advisor。源码解析如下:

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    //如果是 IntroductionAdvisor 则拿 PointCut 进行过滤
    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 {
        // 如果没有任何匹配默认返回 true
        return true;
    }
}
复制代码

通过 extendAdvisors 进行扩展

再看 extendAdvisors 到底是扩展了啥玩意。扩展代码主要是调用了 AspectJProxyUtilsmakeAdvisorChainAspectJCapableIfNecessary。这个方法的作用是给刚才过滤好的 Advisors 链上加上 ExposeBeanNameAdvisors 这个比较特殊的 Adviors。而 ExposeBeanNameAdvisors 的作用是在调用那一步的时候,用来传递 MethodInvocation 的。我们简单看一下代码:

public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
    // 如果为空则不需要执行
    if (!advisors.isEmpty()) {
        boolean foundAspectJAdvice = false;
        for (Advisor advisor : advisors) {
            // Be careful not to get the Advice without a guard, as
            // this might eagerly instantiate a non-singleton AspectJ aspect
            // 确认是否为切面
            if (isAspectJAdvice(advisor)) {
                foundAspectJAdvice = true;
            }
        }
        //如果没有 ExposeInvocationInterceptor 则添加
        if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
            advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
            return true;
        }
    }
    return false;
}

private static boolean isAspectJAdvice(Advisor advisor) {
    return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
            advisor.getAdvice() instanceof AbstractAspectJAdvice ||
            (advisor instanceof PointcutAdvisor &&
                     ((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
复制代码

对 Advisor 进行排序

最后瞧瞧主要是通过哪些元素进行排序的。其实在 Spring Boot 里面,主要排序是通过 @Order 注解实现的。通过比较器 AnnotationAwareOrderComparator 实现。有兴趣可以看看它的 findOrder 方法。

createProxy

createProxy 方法主要是 AbstractAutoProxyCreator 方式实现的。

如果你对 AOP 还需要另外的扩展,可以继承 BeanNameAutoProxyCreator 或 AbstractAutoProxyCreator 来做进一步的增强

我想说一下 createProxy 主要做了些什么。步骤是

  1. 创建 ProxyFactory
  2. 判断决定对于给定的 bean 是否应该使用 targetClass 而不是他的接口代理
  3. 通过 buildAdvisors 方法创建 Advisor
  4. proxyFactory 设置对应的信息包括 advisors、目标对象、是否允许子类提前过滤需要被执行的 Advisor 以及调用模板方法 customizeProxyFactory 来配置 proxyFactory
  5. 最后调用 proxyFactory.getProxy 进行动态代理
protected Object createProxy(
        Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
	// 如果是 ConfigurableListableBeanFactory 可以将 TargetSource 进行暴露
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    //创建 ProxyFactory,将切面的配置信息进行复制
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    //增强器的封装
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    //设置要代理的类 
    proxyFactory.addAdvisors(advisors);
    //设置要代理的类 
    proxyFactory.setTargetSource(targetSource);
    //为子类提供了定制的函数customizeProxyFactory
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(getProxyClassLoader());
}
复制代码

ok!上面大致上的代码已经讲完了加载这个流程。你说"啥?Spring AOP 的实现原理不是 JDK Dynamic ProxyCglib 吗?我怎么一点代码都没看到?我面试的时候可是背的妥妥的"。莫慌,现在我开始单独讲这一部分,因为它很重要也很长。

ProxyFactory.getProxy()

讲之前我先介绍一些类 ProxyFactory / ProxyCreatorSupport / AdvisedSupport ProxyConfig / Advised

 说明 
ProxyFactory 装饰工具类,对外提供 API
ProxyCreatorSupport 代理基础工厂,提供可配置的 AopProxyFactory 以及代理监听器
AdvisedSupport AOP 代理配置管理器的基类,提供拦截链、接口缓存、是否提前过滤参数等等
ProxyConfig 最高父类,保证全局参数一致

前面我们已经设置好了 ProxyFactory 的属性,现在开始调用 getProxy 来获取代理类。

public Object getProxy(ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}
复制代码

上面的 createAopProxy 其实就是获取 ProxyCreatorSupport 中设置的 aopProxyFactory。如果你看 createAopProxy 你会发现它会将自身作为参数传入,这就是 AdvisedSupport 的作用。

继续往下走的话,我们会调用 getProxy() 方法。

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}
复制代码

实际上返回的是 AopProxy。这下重点来了,实际上 AopProxy 有两个子类:CglibAopProxyJdkDynamicAopProxy。这就是 JDK 代理以及 Cglib 代理。

我们来看看 JdkDynamicAopProxy 是怎么样的。源代码里面,JdkDynamicAopProxy 实现了 InvocationHandler 接口,这个也符合 Java 原生动态代理实现的标准。既然实现了 InvocationHandler,那么当调用其目标方法时候,肯定也是调用它的 invoke 方法。让我们来看看

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    try {
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // 如果調用的方法是 equals
            return equals(args[0]);
        }
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // 如果調用的方法是 hashCode
            return hashCode();
        }
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        //DecoratingProxy的方法和Advised接口的方法  都是是最终调用了config
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            //通过反射调用
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;
		//查看是否“暴露代理”,为 true 则设置 proxy
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // 尽量延迟获取对象的时间,因为这个目标对象可能来源于对象池或别的地方
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 获取当前方法的调用链条
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // 如果链条为空,直接调用
        if (chain.isEmpty()) {
            //减少创建 MethodInvocation 的机会,可以直接调用方法即可
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            // 创建 ReflectiveMethodInvocation,这个是为了结合调用链以及 法 进行原型链调用
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 通过方法的调用链处理 joinpoint
            retVal = invocation.proceed();
        }

        // 获取方法返回值的类型,处理返回的信息
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // 如果返回值等于目标对象,只能直接返回 Proxy 对象
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            //throw Exception
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            // 预留模板方法来释放对象(一般是一些拥有对象池的需要实现此方法)
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // 重置为旧的代理对象
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
复制代码

exposeProxy 主要是解决嵌套方法代理的问题。举个例子

class A {
	@Transactional(propagation = Propagation.REQUIRED)
    public void a() {
    	this.b();
    }
    
    @Transactional(propagation = Propagation.REQUIRED_NEW)
    public void b() {
    	System.out.println("method b");
    }
}
复制代码

上面的例子中,b 方法是不会被切面拦截的。因为 b 方法属于 a 方法的内部调用。那么如 b 方法也实现 AOP 那么只能通过 expose-proxy 属性。

上面大致上是 JdkDynamicAopProxy 的代理方式。下面来看看属于 Cglib 的 ObjenesisCglibAopProxyCglib 方式主要是在创建的时候已经准备好拦截方法进行生成代理类了。

public Object getProxy(ClassLoader classLoader) {
     //throw code

    try {
        Class<?> rootClass = this.advised.getTargetClass();

        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            //循环父类接口,保存
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // 校验
        validateClassIfNecessary(proxySuperClass, classLoader);

        // 配置 CGLIB 增强
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
		//根据 Class 获取拦截方法
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        // fixedInterceptorMap 在 getCallbacks 后调用
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        //生成代理并实例化
        return createProxyClassAndInstance(enhancer, callbacks);
    }
    
    //throw Exception
}
复制代码

获取 Proxy 的过程中,我们会去根据 TargetSource 获取对应的拦截方法。获取的方法是 getCallbacks

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    // 优化的参数
    boolean exposeProxy = this.advised.isExposeProxy();
    boolean isFrozen = this.advised.isFrozen();
    boolean isStatic = this.advised.getTargetSource().isStatic();

    // 选择 AOP 的拦截器
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

    // 是否暴露对象
    Callback targetInterceptor;
    if (exposeProxy) {
        targetInterceptor = isStatic ?
                new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
    }
    else {
        targetInterceptor = isStatic ?
                new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
    }

    Callback targetDispatcher = isStatic ?
            new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();

    Callback[] mainCallbacks = new Callback[] {
            aopInterceptor,  // for normal advice
            targetInterceptor,  // invoke target without considering advice, if optimized
            new SerializableNoOp(),  // no override for methods mapped to this
            targetDispatcher, this.advisedDispatcher,
            new EqualsInterceptor(this.advised),
            new HashCodeInterceptor(this.advised)
    };

    Callback[] callbacks;

    // 如果目标是静态的并且通知链被冻结,然后我们可以通过发送AOP调用来进行一些优化,对该方法使用固定链直接指向目标。
    if (isStatic && isFrozen) {
        Method[] methods = rootClass.getMethods();
        Callback[] fixedCallbacks = new Callback[methods.length];
        this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);

        //循环方法
        for (int x = 0; x < methods.length; x++) {
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
            fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                    chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
            this.fixedInterceptorMap.put(methods[x].toString(), x);
        }

        // 复制 callbacks
        callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
        System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
        System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
        this.fixedInterceptorOffset = mainCallbacks.length;
    }
    else {
        callbacks = mainCallbacks;
    }
    return callbacks;
}
复制代码

一系列配置后,Spring 生成代理并实例化。

protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    Class<?> proxyClass = enhancer.createClass();
    Object proxyInstance = null;

    if (objenesis.isWorthTrying()) {
        try {
            proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
        }
        catch (Throwable ex) {
            //throw Exception
        }
    }

    if (proxyInstance == null) {
        // 如果 proxyInstance 为 null 就使用常规构造器进行初始化啊
        try {
            proxyInstance = (this.constructorArgs != null ?
                    proxyClass.getConstructor(this.constructorArgTypes).newInstance(this.constructorArgs) :
                    proxyClass.newInstance());
        }
        catch (Throwable ex) {
            //throw Exception
        }
    }

    ((Factory) proxyInstance).setCallbacks(callbacks);
    return proxyInstance;
}
复制代码

最后,Cglib 与 JDK Proxy 也类似,会调用一个类似 invoke 的方法。在 Cglib 中主要有几个实现:

类名 说明 
StaticUnadvisedInterceptor 没有 advise 的静态方法拦截器调用
StaticUnadvisedExposedInterceptor 没有 advise 的静态方法拦截器,但是需要暴露 proxy 的
DynamicUnadvisedInterceptor 没有 advise 的动态方法拦截器调用
DynamicUnadvisedExposedInterceptor 没有 advise 的动态方法拦截器,但是需要暴露 proxy 的
StaticDispatcher 保证返回值不是 this
EqualsInterceptor equals 方法拦截器
HashCodeInterceptor hashCode 方法拦截器
FixedChainStaticTargetInterceptor 拦截器专门用于冻结的静态代理上的 advise
DynamicAdvisedInterceptor 有 advise 的动态方法拦截器

由于我们一般多数是 有 advise 的动态方法拦截器,所以看 DynamicAdvisedInterceptor#intercept 方法。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Class<?> targetClass = null;
    Object target = null;
    try {
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 延迟获取对象的时间,因为这个目标对象可能来源于对象池
        target = getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }
        //获取调用链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        // 如果没有 advice 直接调用方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 创建 CglibMethodInvocation,并且进行调用
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    }
    finally {
        //释放
        if (target != null) {
            releaseTarget(target);
        }
        //重置旧的 Proxy
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
复制代码

一个简单的 AOP 例子

通过上面的源码解析,我们知道了 Spring AOP 实际上就是 4 个步骤:

  1. 应用启动的时候,对 AOP 相关的配置类进行读取
  2. 然后通过 Spring 的扩展函数,处理需要被代理的目标对象
  3. 根据目标对象获取拦截链,然后进行参数赋值
  4. 最后进行代理实例化,返回替换原来的目标类

那我们也可以模仿 Spring 实现一个 AOP 的例子。

  1. 首先我们创建一个切面类 Aspects,里面包含了各种通知(前置,后置等,对标 SpringMethodBeforeAdvice
  2. 然后我们编写实现了 AspectsSimpleAspect,这个默认拦截都通过的。
  3. 然后我们编写一个 LogAspect 继承 SimpleAspect,这个 LogAspect 可以重写父类自己感兴趣的方法
  4. 然后我们编写一个使用 JDK Dynamic Proxy 的代理生成类 JdkDynamicAopProxy (对标 Spring 的 JdkDynamicAopProxy
  5. 然后我们编写一个 TargetSource 作为代理数据源
  6. 上面的基础 AOP 代码写完了,我们开始写一个业务接口以及实现类 UserServiceUserServceImpl(记住是因为 JDK Dynamic Proxy 需要接口)
  7. 最后我们编写测试类来测试

第一步

public interface Aspects {

    boolean before(Object target, Method method, Object[] args);

    boolean after(Object target, Method method, Object[] args);

    boolean afterException(Object target, Method method, Object[] args, Throwable e);

}
复制代码

' 第二步

public class SimpleAspect implements Aspects{
    @Override
    public boolean before(Object target, Method method, Object[] args) {
        return true;
    }

    @Override
    public boolean after(Object target, Method method, Object[] args) {
        return true;
    }

    @Override
    public boolean afterException(Object target, Method method, Object[] args, Throwable e) {
        return true;
    }
}
复制代码

第三步

public class LogAspect extends SimpleAspect{
    @Override
    public boolean before(Object target, Method method, Object[] args) {
        System.out.println("log in the time " + System.currentTimeMillis());
        return true;
    }
}
复制代码

第四步

public class JdkDynamicAopProxy implements InvocationHandler {

    private TargetSource target;
    private Aspects aspect;

    //构造器
    public JdkDynamicAopProxy(TargetSource target, Aspects aspect) {
        this.target = target;
        this.aspect = aspect;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        final Object target = this.target.getTarget();
        final Aspects aspects = this.aspect;

        Object result = null;
        if (aspects.before(target, method, args)) {     //调用前置
            result = method.invoke(target, args==null ? null : args);
        }

        if (aspects.after(target, method, args)) {  //后置
            return result;
        }
        return null;
    }
}
复制代码

第五步

public class TargetSource {
    private Object target;
    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }
}
复制代码

第六步 UserService 接口

public interface UserService {
    public void show();
}
复制代码

实现类

public class UserServiceImpl implements UserService{
    public void show(){
        System.out.println("User create");
    }
}
复制代码

最后一步

public class AopTest {
    public static void main(String[] args) {
        //创建一个切面
        Aspects aspects = new LogAspect();
        TargetSource targetSource = new TargetSource();
        UserServiceImpl userService = new UserServiceImpl();
        targetSource.setTarget(userService);
        //创建代理类,调用方法
        JdkDynamicAopProxy jdkProxyIntercept = new JdkDynamicAopProxy(targetSource, aspects);
        UserService userService1 = (UserService)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{UserService.class}, jdkProxyIntercept);
        userService1.show();
    }
}
复制代码

输出结果为

log in the time 1605582637979
User create
复制代码

上面的例子是一个非常简单完整的例子,所以它没有考虑非常多的东西,例如

  1. 解决嵌套通知(通过责任链调用)
  2. 考虑拦截的方式如果是 equalshashCode、静态方法等的处理
  3. 目前是硬编码方式判断,AOP 如果是随时随地添加拦截器如何解决?
  4. 以及更多...

建议如果想深究的同学可以去看一下 Spring AOP 实现的每一个细节。

结语

至此,Spring AOP 的源码完全讲完了。说实话,的确有一些概念或者问题是需要通过源码才能发现的。而且看源码的过程中,一般来说不仅仅是需要把大概流程掌握,而且还要具备对一定细节的追问,才能更加深刻的把握。

免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

java

1

相关文章推荐

未登录头像

暂无评论