Spring系列|Spring AOP 创建 AopProxy 代理对象原理分析

Spring AOP 创建 AopProxy 代理对象原理分析
文章目录

  • Spring AOP 创建 AopProxy 代理对象原理分析
    • 前言
    • 项目环境
    • 相关文章
    • 1.设计原理
    • 2.配置 ProxyFactoryBean
    • 3.AopProxy 的生成过程
    • 4.ProxyFactoryBean 生成 AopProxy 代理对象
      • 4.1 getObject
      • 4.2 initializeAdvisorChain
      • 4.3 getSingletonInstance
      • 4.4 createAopProxy
    • 5.JDK 生成 AopProxy 代理对象
    • 6.CGLIB 生成 AopProxy 代理对象
    • 7.总结
    • 8.参考

前言 本章开始我们将介绍一些 Spring AOP 具体的设计和实现。
项目环境
  • Java 8
  • Spring framework 5.2.2.RELEASE
  • github 地址:https://github.com/huajiexiewenfeng/spring-aop-demos
    • 本章模块:proxy
相关文章
  • Spring AOP 基础概述
  • Spring AOP 的设计与实现
  • Spring AOP 创建 AopProxy 代理对象原理分析
  • Spring AOP 拦截器调用的实现
  • 彩蛋:Spring AOP 和 IoC 以及容器启动之间有何关联?
1.设计原理 在 Spring AOP 模块中,一个主要的部分是代理对象的生成,而对于 Spring 应用,可以看到是通过配置和调用 Spring 的 ProxyFactoryBean 来完成这个任务的。在 ProxyFactoryBean 中封装了主要代理对象的生产过程。在这个过程中,可以使用 JDK 和 CGLIB 两种方式生成。以 ProxyFactoryBean 的设计为中心,相关的类继承关系图如下:
Spring系列|Spring AOP 创建 AopProxy 代理对象原理分析
文章图片

在这个类的继承关系中,可以看到完成 AOP 应用的类,比如 ProxyFactory、AspectJProxyFactory、ProxyFactoryBean,他们都在同一个类的基础体系下,都是 ProxyConfig、AdvisedSupport、ProxyCreatorSupport 的子类。
  • 作为共同基类,可以将 ProxyConfig 看成是一个数据基类,这个数据基类为 ProxyFactoryBean 这样的子类提供了配置属性。
  • 在另一个基类 AdvisedSupport 的实现中,封装了 AOP 对通知器的相关操作,这些操作对于不同的 AOP 代理对象的生产都是一样的,单对象语句的 AOP 代理对象的创建,AdvisedSupport 把它们交给子类去完成。
  • 对于 ProxyCreatorSupport,可以将它看到是其子类创建 AOP 代理对象的一个辅助类。
通过继承以上提到的基类功能,具体的 AOP 代理对象的生产,根据不同的需求,分别由 ProxyFactory、AspectJProxyFactory、ProxyFactoryBean 来完成。
对于需要使用 AspectJ 的 AOP 应用,AspectJProxyFactory 起到集成 Spring 和 AspectJ 的作用;对于使用 Spring AOP 的应用,ProxyFactoryBean 和 ProxyFactory 都提供了 AOP 功能的封装,只是使用 ProxyFactoryBean ,可以在 IoC 容器中完成声明式配置,而使用 ProxyFactory ,则需要编程式的使用 Spring AOP 功能。
2.配置 ProxyFactoryBean 从这部分开始,进入到 Spring AOP 的实现部分,在分析 Spring AOP 的实现原理中,主要以 ProxyFactoryBean 的实现作为例子来进行分析。因为 ProxyFactoryBean 是 Spring IoC 环境中创建的 AOP 应用的底层方法,也是最灵活的方法,Spring 通过他完成了对 AOP 使用的封装。我们以 ProxyFactoryBean 的实现为入口,来逐层深入。
首先我们需要了解 ProxyFactoryBean 的配置和使用,通过 XML 的方式来配置 ProxyFactoryBean 和 AOP。
  • 定义使用的通知器 Advisor,这个通知器应该作为一个 Bean 来定义。这个通知器的实现定义了需要对目标对象进行增强的切面行为,也就是 Advice 通知。
  • 定义 ProxyFactoryBean ,把它做诶了一个 Bean 来定义,它是封装 AOP 功能的主要类。在配置 ProxyFactoryBean 时,需要设定与 AOP 实现相关的重要属性,比如 proxyInterface、interceptorNames、target 等等。
  • 定义 target 属性,作为 target 属性注入的 Bean,是需要用 AOP 通知器中的切面应用来增强的对象,也就是前面提到的 base 对象(《Spring AOP 基础概述》)。
有了上述配置之后,就可以使用 ProxyFactoryBean 完成 AOP 的基本功能了。
配置示例:
com.csdn.spring.aop.proxy.factorybean.TestInterface testAdvisor

掌握这些配置后,就可以具体看一看这些 AOP 是如何实现的,切面应用怎样通过 ProxyFactoryBean 对 target 对象起作用,下面我们继续详细的进行分析。
3.AopProxy 的生成过程 在 Spring AOP 的使用中,我们了解到,可以通过 ProxyFactoryBean 来配置目标对象和切面行为。在 ProxyFactoryBean 中,通过 interceptorNames 属性来配置以及定义好的通知器 Advisor。虽然名称是 interceptorNames,但是实际上是提供 AOP 应用配置通知器的地方。
在 ProxyFactoryBean 中需要为 target 目标对象生成 Proxy 代理对象,从而为 AOP 切面的组织做好准备工作。这些具体的代理对象生成工作是通过 JDK 的 Proxy 或者 CGLIB 来完成的。
生成过程如图所示:
Spring系列|Spring AOP 创建 AopProxy 代理对象原理分析
文章图片

4.ProxyFactoryBean 生成 AopProxy 代理对象 ProxyFactoryBean 的 AOP 实现需要依赖 JDK 或者 CGLIB 提供的 Proxy 特性。从 FactoryBean 中获取对象,是以 getObject() 方法作为入口完成的;ProxyFactoryBean 实现中的 getObject 方法,是 FactoryBean 需要实现的接口。对 ProxyFactoryBean 来说,把需要对 target 目标对象增加增强处理,来通过 getObject 方法进行封装。这些增强处理是为 AOP 功能的实现提供服务的。
4.1 getObject
  • org.springframework.aop.framework.ProxyFactoryBean#getObject
    • 首先对通知器链进行初始化,通知器链封装了一系列的拦截器,这些拦截器都要从配置中读取,然后为代理对象的生成做好准备。
    • 在生成代理对象时,需要根据 Bean 的定义来判断作用域,生成不同的对象实例。
      • 不了解作用域( Scope),可以参考相关文章 - 《Spring Bean 作用域》
public Object getObject() throws BeansException { // 初始化通知器链 initializeAdvisorChain(); // 判断 Bean 的作用域,生成对应的 proxy 对象 if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.info("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } }

4.2 initializeAdvisorChain
为 Proxy 代理对象配置 Advisor 链是在 initializeAdvisorChain 方法中完成的,代码如下:
  • advisorChainInitialized 是一个标志位,表示通知器链是否已经初始化,如果已经初始化,就不会再初始化,直接返回。
  • 初始化工作发生在第一次通过 ProxyFactoryBean 去获取代理对象的时候。
  • 在完成这个初始化之后,接着读取配置中出现的所有通知器,这个过程是通过 getBean 依赖查找完成。
  • 然后将取得的通知器加入到连接器链中,这个动作是由 addAdvisorOnChainCreation 来完成。
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { if (this.advisorChainInitialized) { return; // 通知器链已经初始化,直接返回 }// 异常检查,比如通知器链为空 ... // Materialize interceptor chain from bean names. // 循环遍历拦截器 for (String name : this.interceptorNames) { if (logger.isTraceEnabled()) { logger.trace("Configuring advisor or advice '" + name + "'"); }if (name.endsWith(GLOBAL_SUFFIX)) {// 以 * 结尾 if (!(this.beanFactory instanceof ListableBeanFactory)) { throw new AopConfigException( "Can only use global advisors or interceptors with a ListableBeanFactory"); } // 添加 Advisor 链的调用 addGlobalAdvisor((ListableBeanFactory) this.beanFactory, name.substring(0, name.length() - GLOBAL_SUFFIX.length())); }else { // If we get here, we need to add a named interceptor. // We must check if it's a singleton or prototype. // 如果程序在这里被调用,那么需要加入命名的拦截器 advice,并且需要检查这个 Bean 的作用域类型 Object advice; if (this.singleton || this.beanFactory.isSingleton(name)) { // Add the real Advisor/Advice to the chain. // 通过依赖查找更加名称获取 advice advice = this.beanFactory.getBean(name); } else { // It's a prototype Advice or Advisor: replace with a prototype. // Avoid unnecessary creation of prototype bean just for advisor chain initialization. // 对原型类型Bean 的处理 advice = new PrototypePlaceholderAdvisor(name); } addAdvisorOnChainCreation(advice, name); } } }this.advisorChainInitialized = true; }

4.3 getSingletonInstance
生成 singleton 的代理对象在 getSingletonInstance 方法中完成,这个方法是 ProxyFactoryBean 生成 AopProxy 代理对象的调用入口。代理对象会封装对 target 目标对象的调用,也就是说针对 target 对象的方法调用行为会被这里生成的代理对所拦截。生成步骤如下:
  • 首先读取 ProxyFactoryBean 中的配置,为生成代理对象做好必要的准备,比如设置代理的方法调用接口等。
  • Spring 通过 AopProxy 类来具体生成代理对象。
org.springframework.aop.framework.ProxyFactoryBean#getSingletonInstance 源码如下:
private synchronized Object getSingletonInstance() { if (this.singletonInstance == null) { this.targetSource = freshTargetSource(); if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { // Rely on AOP infrastructure to tell us what interfaces to proxy. // 根据 AOP 框架来判断需要代理的接口 Class targetClass = getTargetClass(); if (targetClass == null) { throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy"); } // 这里设置代理对象的接口 setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); } // Initialize the shared singleton instance. super.setFrozen(this.freezeProxy); // 注意这里的方法会使用 ProxyFactory 来生成需要的 Proxy this.singletonInstance = getProxy(createAopProxy()); } return this.singletonInstance; }

这里出现了 AopProxy 类型的对象,Spring 利用这个 AopProxy 接口类把 AOP 嗲你对象的实现与框架的其他部分有效的分离开来,AopProxy 是一个接口,它有两个子类实现分别是 CglibAopProxy 和 JdkDynamicAopProxy,从名称就可以看出一个是 CGLIB 的实现,一个是 JDK 动态代理的实现。
4.4 createAopProxy
最终这个 createAopProxy 的核心实现方法如下:
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
  • 如果目标对象是接口类或者本身就是一个 Proxy 生成的代理类,那么使用 JDK 来生成代理对象
  • 否则使用 CGLIB 来生成代理对象
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."); } // 如果目标类是接口或者是一个Proxy生成的代理类 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 使用 CGLIB 生成 return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }

【Spring系列|Spring AOP 创建 AopProxy 代理对象原理分析】下面我们会详细讨论 JDK 和 CGLIB 如何生成 AopProxy 的具体过程。
5.JDK 生成 AopProxy 代理对象 在 JdkDynamicAopProxy 中,使用了 JDK 的 Proxy 类来生成代理对象,首先需要从 advised 对象中取得代理对象的代理接口配置,然后调用 Proxy 的 newProxyInstance 方法生成代理对象。
在生产代理对象时,需要指明三个参数
  • 类加载器
  • 代理接口
  • Proxy 回调方法所在的对象,这个对象需要实现 InvocationHandler 接口
而 JdkDynamicAopProxy 这个类实现了 InvocationHandler 接口和 invoke 方法,所以 Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 中的这个 this 可以将 JdkDynamicAopProxy 指派给 Proxy 对象,换言之,JdkDynamicAopProxy 对象本身在 Proxy代理的接口方法被调用时,会触发 invoke 方法的回调,这个回调方法完成了 AOP 实现的封装。
org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }

6.CGLIB 生成 AopProxy 代理对象 我们继续来看 CGLIB 来生成 Proxy 代理对象的实现,代码如下:
public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource()); }try { // 从 advised 中取得 IoC 容器配置的 Target 对象 Class rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class proxySuperClass = rootClass; if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { proxySuperClass = rootClass.getSuperclass(); Class[] additionalInterfaces = rootClass.getInterfaces(); for (Class additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } }// Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass, classLoader); // Configure CGLIB Enhancer... // 创建配置配置 CGLIB 的 Enhancer,这个 Enhancer 是 CGLIB 的主要操作类 Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } // 设置 enhancer 对象,包括设置代理接口、回调用法 // 来自 advised 的 IoC 配置,比如使用 AOP 的 DynamicAdvisedInterceptor 拦截器 enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); Callback[] callbacks = getCallbacks(rootClass); Class[] types = new Class[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance. // 通过 enhancer 生成代理对象 return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", ex); } catch (Throwable ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } }

在上面的源代码清单中,可以看到具体对 CGLIB 的使用,比如 Enhancer 对象的配置,以及通过 Enhancer 生产代理对象。在这个生产代理对象的过程中,Enhancer 对象 callback 回调的设置,正是这些回调封装了 Spring AOP 的实现,就想前面介绍的 JDK 的 Proxy 对象的 invoke 回调方法一样。在 Enhancer 设置 callback 回调过程中,实际上是通过 DynamicAdvisedInterceptor 拦截器来完成 AOP 功能的,这个会在下一篇文章说到。
这样,通过使用 AopProxy 对象封装 target 目标对象之后,ProxyFactoryBean 的 getObject 方法得到的对象就不是一个普通的 Java 对象了,而是一个 AopProxy 代理对象。
在 ProxyFactoryBean 中配置的 target 目标对象,这时已经不会被直接调用其方法实现,而是作为 AOP 实现的一部分。对 target 目标对象的方法调用,首先被 AopProxy 拦截。对不同的 AopProxy 代理对象生成方式,会使用不同的拦截回调入库。例如,对于 JDK 的 AopProxy 代理对象,使用的是 InvocationHandler 的 invoke 回调入口;而对于 CGLIB 的 AopProxy 代理对象,使用的是设置好的 callback回调。
7.总结 可以将 AOP 的实现部分看成两个部分
  • 基础设施准备
  • AOP运行辅助
这里的 AopProxy 代理对象的生成,可以看成是一个静态的 AOP 基础设施建立过程。通过这个准备过程,将代理对象、拦截器这些待调用的部分都准备好,等待着 AOP 运行过程中对这些基础设施的使用。对于应用触发的 AOP 应用,会涉及 AOP 框架的运行和对 AOP 基础设计的使用。这些动态运行部分,是从前面提到的拦截器回调入口开始的,这些拦截器调用的实现原理和 AopProxy 代理对象生产一样,也是 AOP 实现的重要组成部分,下一章我们来详细讨论。
8.参考
  • 《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》- 计文柯

    推荐阅读