死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象

时间:2022-10-19 12:18:10

该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读。

Spring 版本:5.1.14.RELEASE

在开始阅读 Spring AOP 源码之前,需要对 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 - 文章导读》 这一系列文章

了解 AOP 相关术语,可先查看 《Spring AOP 常见面试题) 》 这篇文章

该系列其他文章请查看:《死磕 Spring 之 AOP 篇 - 文章导读》

在前面的《Spring AOP 自动代理(一)入口》文章中,分析了 Spring AOP 自动代理的入口是 AbstractAutoProxyCreator 对象,其中自动代理的过程主要分为下面两步:

  1. 筛选出能够应用于当前 Bean 的 Advisor
  2. 找到了合适 Advisor 则创建一个代理对象, JDK 动态代理或者 CGLIB 动态代理

上一篇《Spring AOP 自动代理(二)筛选合适的通知器》文章分析了上面第 1 步的处理过程,先去解析出当前 IoC 容器所有 Advisor 对象,包括 Advisor 类型的 Bean 和从 @AspectJ 注解的 Bean 解析出来的 Advisor 对象;然后通过通过 ClassFilter 类过滤器和 MethodMatcher 方法匹配器筛选出能够应用于这个 Bean 的 Advisor 们,最后进行排序;不同的 AspectJ 根据 @Order 排序,同一个 AspectJ 中不同 Advisor 的排序,优先级:AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice

本文将会分析上面的第 2 的创建过程,如果这个 Bean 有合适的 Advisor,那么为这个 Bean 创建一个代理对象,我们一起来看看是如何创建代理对象的。

回顾

// AbstractAutoProxyCreator.java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
/*
* <1> 如果当前 Bean 已经创建过自定义 TargetSource 对象
* 表示在上面的**实例化前置处理**中已经创建代理对象,那么直接返回这个对象
*/
if (StringUtils.hasLength(beanName)
&& this.targetSourcedBeans.contains(beanName))
{
return bean;
}
// <2> `advisedBeans` 保存了这个 Bean 没有必要创建代理对象,则直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
/*
* <3> 不需要创建代理对象,则直接返回当前 Bean
*/
if (isInfrastructureClass(bean.getClass()) // 如果是 Spring 内部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 标记接口)
|| shouldSkip(bean.getClass(), beanName)) // 应该跳过
{
// 将这个 Bean 不需要创建代理对象的结果保存起来
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
} // Create proxy if we have advice.
// <4> 获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// <5> 如果有 Advisor,则进行下面的动态代理创建过程
if (specificInterceptors != DO_NOT_PROXY) {
// <5.1> 将这个 Bean 已创建代理对象的结果保存至 `advisedBeans`
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// <5.2> 创建代理对象,JDK 动态代理或者 CGLIB 动态代理
// 这里传入的是 SingletonTargetSource 对象,可获取代理对象的目标对象(当前 Bean)
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// <5.3> 将代理对象的 Class 对象(目标类的子类)保存
this.proxyTypes.put(cacheKey, proxy.getClass());
// <5.4> 返回代理对象
return proxy;
} // <6> 否则,将这个 Bean 不需要创建代理对象的结果保存起来
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// <7> 返回这个 Bean 对象
return bean;
}

在创建代理对象的过程中,上面方法的第 4 步尝试获取能够应用于当前 Bean 的 Advisor,该过程在上一篇文章中进行分析过,如果有 Advisor,则调用 createProxy(..) 方法创建代理对象

注意,这里传入的 TargetSource 是一个 SingletonTargetSource 对象,可获取目标对象,如下:

public class SingletonTargetSource implements TargetSource, Serializable {
private static final long serialVersionUID = 9031246629662423738L; private final Object target; public SingletonTargetSource(Object target) {
Assert.notNull(target, "Target object must not be null");
this.target = target;
} @Override
public Class<?> getTargetClass() {
return this.target.getClass();
} @Override
public Object getTarget() {
return this.target;
} @Override
public void releaseTarget(Object target) {
// nothing to do
} @Override
public boolean isStatic() {
return true;
}
}

创建代理对象的流程

  1. 创建一个 ProxyFactory 代理工厂对象,设置需要创建的代理类的配置信息,例如 Advisor 数组和 TargetSource 目标类来源

  2. 借助 DefaultAopProxyFactory 选择 JdkDynamicAopProxy(JDK 动态代理)还是 ObjenesisCglibAopProxy(CGLIB 动态代理)

    • proxy-target-classfalse 时,优先使用 JDK 动态代理,如果目标类没有实现可代理的接口,那么还是使用 CGLIB 动态代理

    • 如果为 true,优先使用 CGLIB 动态代理,如果目标类本身是一个接口,那么还是使用 JDK 动态代理

  3. 通过 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy 创建一个代理对象

    • JdkDynamicAopProxy 本身是一个 InvocationHandler 实现类,通过 JDK 的 Proxy.newProxyInstance(..) 创建代理对象
    • ObjenesisCglibAopProxy 借助 CGLIB 的 Enhancer 创建代理对象,会设置 Callback 数组和 CallbackFilter 筛选器(选择合适 Callback 处理对应的方法),整个过程相比于 JDK 动态代理更复杂点,主要的实现在 DynamicAdvisedInterceptor 方法拦截器中

AbstractAutoProxyCreator

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator:AOP 自动代理的抽象类,完成主要的逻辑实现,提供一些骨架方法交由子类完成

1. createProxy 方法

createProxy(..) 方法,为目标对象创建一个代理对象,如下:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
// 为目标 Bean 的 BeanDefinition 对象设置一个属性
// org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass -> 目标 Bean 的 Class 对象
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
} // <1> 创建一个代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// <2> 复制当前 ProxyConfig 的一些属性(例如 proxyTargetClass、exposeProxy)
proxyFactory.copyFrom(this); /**
* <3> 判断是否类代理,也就是是否开启 CGLIB 代理
* 默认配置下为 `false`,参考 {@link org.springframework.context.annotation.EnableAspectJAutoProxy}
*/
if (!proxyFactory.isProxyTargetClass()) {
/*
* <3.1> 如果这个 Bean 配置了进行类代理,则设置为 `proxyTargetClass` 为 `true`
*/
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
/*
* <3.2> 检测当前 Bean 实现的接口是否包含可代理的接口
* 如没有实现,则将 `proxyTargetClass` 设为 `true`,表示需要进行 CGLIB 提升
*/
evaluateProxyInterfaces(beanClass, proxyFactory);
}
} /*
* <4> 对入参的 Advisor 进一步处理,因为其中可能还存在 Advice 类型,需要将他们包装成 DefaultPointcutAdvisor 对象
* 如果配置了 `interceptorNames` 拦截器,也会添加进来
*/
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// <5> 代理工厂添加 Advisor 数组
proxyFactory.addAdvisors(advisors);
// <6> 代理工厂设置 TargetSource 对象
proxyFactory.setTargetSource(targetSource);
// <7> 对 ProxyFactory 进行加工处理,抽象方法,目前没有子类实现
customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy);
// <8> 是否这个 AdvisedSupport 配置管理器已经过滤过目标类(默认为 false)
if (advisorsPreFiltered()) {
// 设置 `preFiltered` 为 `true`
// 这样 Advisor 们就不会根据 ClassFilter 进行过滤了,而直接通过 MethodMatcher 判断是否处理被拦截方法
proxyFactory.setPreFiltered(true);
} // <9> 通过 ProxyFactory 代理工厂创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}

该方法的处理过程如下:

  1. 创建一个 ProxyFactory 代理工厂 proxyFactory
  2. 复制当前对象的一些属性给 proxyFactory(例如 proxyTargetClass、exposeProxy),当前 AbstractAutoProxyCreator 对象继承了 ProxyConfig
  3. 判断是否类代理,也就是是否开启 CGLIB 代理,默认配置下为 false,如果没有的话,进行下面处理
    1. 如果这个 Bean 配置了进行类代理,则设置为 proxyTargetClasstrue
    2. 否则,检测当前 Bean 实现的接口是否包含可代理的接口,如没有实现,则将 proxyTargetClass 设为 true,表示需要进行 CGLIB 提升
  4. 调用 buildAdvisors(..) 方法,对入参的 Advisor 数组进一步处理,会将不是 Advisor 类型的对象包装成 DefaultPointcutAdvisor 对象
  5. proxyFactory 代理工厂添加 Advisor 数组
  6. proxyFactory 代理工厂设置 TargetSource 对象,用户获取目标对象
  7. proxyFactory 进行加工处理,抽象方法,目前没有子类实现
  8. 是否这个 AdvisedSupport 配置管理器已经过滤过目标类(默认为 false
    1. 是的话设置 preFilteredtrue,这样 Advisor 们就不会根据 ClassFilter 进行过滤了,而直接通过 MethodMatcher 判断是否处理被拦截方法
  9. 调用 proxyFactory 代理工厂的 getProxy(@Nullable ClassLoader classLoader) 方法创建代理对象

这个过程不复杂,容易理解,其中第 4 步会再次对 Advisor 数组进一步处理,在第 9 步根据 proxyFactory 创建代理对象

buildAdvisors 方法

buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) 方法,对 Advisor 数组进一步处理,如下:

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// Handle prototypes correctly...
// <1> 将配置的 `interceptorNames` 转换成 Advisor 类型(默认没有)
Advisor[] commonInterceptors = resolveInterceptorNames(); // <2> 将 commonInterceptors 与 specificInterceptors 放入一个集合
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors.length > 0) {
// 是否添加至最前面(默认为 true)
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
/*
* <3> 遍历 `specificInterceptors` 数组
*/
for (int i = 0; i < allInterceptors.size(); i++) {
// <3.1> 将不是 Advisor 类型的 Advice 或者 MethodInterceptor 包装成 DefaultPointcutAdvisor 对象
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
// <4> 返回构建好的 Advisor 数组
return advisors;
}

该方法的处理过程如下:

  1. 将配置的 interceptorNames 转换成 Advisor 类型(默认没有),得到 commonInterceptors 数组,如下:

    private Advisor[] resolveInterceptorNames() {
    BeanFactory bf = this.beanFactory;
    ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
    List<Advisor> advisors = new ArrayList<>();
    for (String beanName : this.interceptorNames) {
    if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
    Assert.state(bf != null, "BeanFactory required for resolving interceptor names");
    Object next = bf.getBean(beanName);
    advisors.add(this.advisorAdapterRegistry.wrap(next));
    }
    }
    return advisors.toArray(new Advisor[0]);
    }

    解析 interceptorNames 中对应的 Bean,并包装成 Advisor 类型(如果需要的话)

  2. 将上一步获取到的 commonInterceptors 数组放入入参中的 specificInterceptors 数组中

  3. 遍历 specificInterceptors 数组

    1. 将不是 Advisor 类型的 Advice 或者 MethodInterceptor 包装成 DefaultPointcutAdvisor 对象

      // DefaultAdvisorAdapterRegistry.java
      @Override
      public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
      if (adviceObject instanceof Advisor) { // Advisor 类型,直接返回
      return (Advisor) adviceObject;
      }
      if (!(adviceObject instanceof Advice)) { // 非 Advice 接口,抛出异常
      throw new UnknownAdviceTypeException(adviceObject);
      }
      Advice advice = (Advice) adviceObject;
      if (advice instanceof MethodInterceptor) { // MethodInterceptor 类型,包装成 DefaultPointcutAdvisor 对象
      // So well-known it doesn't even need an adapter.
      return new DefaultPointcutAdvisor(advice);
      }
      for (AdvisorAdapter adapter : this.adapters) {
      // Check that it is supported.
      // 检查该 Advice 类型是否支持
      if (adapter.supportsAdvice(advice)) {
      // 包装成 DefaultPointcutAdvisor 对象 返回
      return new DefaultPointcutAdvisor(advice);
      }
      }
      throw new UnknownAdviceTypeException(advice);
      }
  4. 返回构建好的 Advisor 数组

能够应用于这个 Bean 的 Advisor 们已经准备好了,那么接下来我们来看看 ProxyFactory 是如何创建代理对象的

2. ProxyFactory

org.springframework.aop.framework.ProxyFactory,代理工厂,如下:

public Object getProxy(@Nullable ClassLoader classLoader) {
// <1> 先创建一个 AOP 代理类(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy)
// <2> 根据 AOP 代理为目标 Bean 创建一个代理对象,并返回
return createAopProxy().getProxy(classLoader);
}

过程分为两步:

  1. 调用 createAopProxy() 方法,创建一个 AOP 代理类(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy),如下:

    protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
    activate();
    }
    // <1> 先获取 AOP 代理工厂,默认为 DefaultAopProxyFactory,只有这个实现
    // <2> 然后通过它根据创建当前 AdvisedSupport 配置管理器创建一个 AOP 代理(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy)
    return getAopProxyFactory().createAopProxy(this);
    }
  2. 然后调用 AOP 代理类的 getProxy(@Nullable ClassLoader classLoader) 方法获取代理对象

可以看到选择 JDK 动态代理还是选择 CGLIB 动态代理在 DefaultAopProxyFactory 中可以找到答案

3. DefaultAopProxyFactory

org.springframework.aop.framework.DefaultAopProxyFactory,默认的 AOP 代理工厂,如下:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
/*
* <1> 判断是否满足下面三个条件的其中一个
*/
if (config.isOptimize() // 需要优化,默认为 `false`
|| config.isProxyTargetClass() // 使用类代理,也就是使用 CGLIB 动态代理
|| hasNoUserSuppliedProxyInterfaces(config) // 目标类没有实现接口
) {
// <1.1> 获取目标类
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.");
}
/*
* <1.2> 如果目标类是一个接口或者是 java.lang.reflect.Proxy 的子类
* 则还是使用 JDK 动态代理,创建一个 JdkDynamicAopProxy 对象,传入 AdvisedSupport 配置管理器,并返回
*/
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// <1.3> 使用 CGLIB 动态代理,创建一个 ObjenesisCglibAopProxy 对象,传入 AdvisedSupport 配置管理器,并返回
return new ObjenesisCglibAopProxy(config);
}
// <2> 否则
else {
// 使用 JDK 动态代理,创建一个 JdkDynamicAopProxy 对象,传入 AdvisedSupport 配置管理器,并返回
return new JdkDynamicAopProxy(config);
}
} private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
} }

创建 AOP 代理类的过程如下:

  1. 判断是否满足下面三个条件的其中一个,则进行下面的处理

    需要优化,默认为 false

    使用类代理,也就是使用 CGLIB 动态代理,在前面的 AbstractAutoProxyCreator#createProxy(..) 方法中有提到过;

    目标类没有实现接口;

    1. 获取目标类
    2. 如果目标类是一个接口或者是 java.lang.reflect.Proxy 的子类,则还是使用JDK 动态代理,创建一个 JdkDynamicAopProxy 对象
    3. 否则,使用 CGLIB 动态代理,创建一个 ObjenesisCglibAopProxy 对象
  2. 否则,使用JDK 动态代理,创建一个 JdkDynamicAopProxy 对象

我们可以看到JDK 动态代理对应 JdkDynamicAopProxy 对象,CGLIB 动态代理对应 ObjenesisCglibAopProxy(继承 CglibAopProxy)对象,在创建这两个对象的时候都传入了一个参数,就是 AdvisedSupport 配置管理器对象。

回到前面的 ProxyFactory#createAopProxy() 方法中,这个 AdvisedSupport 对象就是这个 ProxyFactory 对象,它继承了 AdvisedSupport

再回到 AbstractAutoProxyCreator#createProxy(..) 方法中,这个 ProxyFactory 对象是在这创建的,包含了 TargetSource 目标类来源和能够应用于当前目标对象的所有 Advisor

所以,我们得到的JdkDynamicAopProxy或者ObjenesisCglibAopProxy都包含了创建 AOP 代理对象的所有配置信息,可以创建代理对象了。

通过上面的这个方法,我们还可以得出一个结论,关于 proxy-target-class 配置的含义是什么?

首先这个配置表示是否进行类代理,也就是 CGLIB 动态代理,默认是 false

当为 false 时,优先使用 JDK 动态代理,如果目标类没有实现可代理的接口,那么还是使用 CGLIB 动态代理

如果为 true,优先使用 CGLIB 动态代理,如果目标类本身是一个接口,那么还是使用 JDK 动态代理

到这里,我们知道了使用哪种方式创建代理对象,那么接下里我们一起来看看两种方式创建代理对象的过程。

4. JdkDynamicAopProxy

org.springframework.aop.framework.JdkDynamicAopProxy,JDK 动态代理类,实现了 InvocationHandler 接口,可创建代理对象

构造函数

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 5531744639992436476L; /** We use a static Log to avoid serialization issues. */
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class); /** 代理对象的配置信息,例如保存了 TargetSource 目标类来源、能够应用于目标类的所有 Advisor */
private final AdvisedSupport advised; /** 目标对象是否重写了 equals 方法 */
private boolean equalsDefined; /** 目标对象是否重写了 hashCode 方法 */
private boolean hashCodeDefined; public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 // 没有 Advisor,表示没有任何动作
&& config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) // 没有来源
{
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
}

4.1 getProxy 方法

getProxy() 方法,获取一个 JDK 动态代理对象,如下:

@Override
public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } @Override
public Object getProxy(@Nullable ClassLoader classLoader) {
// <1> 获取需要代理的接口(目标类实现的接口,会加上 Spring 内部的几个接口,例如 SpringProxy)
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// <2> 判断目标类是否重写了 `equals` 或者 `hashCode` 方法
// 没有重写在拦截到这两个方法的时候,会调用当前类的实现
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// <3> 调用 JDK 的 Proxy#newProxyInstance(..) 方法创建代理对象
// 传入的参数就是当前 ClassLoader 类加载器、需要代理的接口、InvocationHandler 实现类
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

获取代理对象的过程如下:

  1. 获取需要代理的接口(目标类实现的接口,会加上 Spring 内部的几个接口,例如 SpringProxy)

  2. 判断目标类是否重写了 equals 或者 hashCode 方法,没有重写在拦截到这两个方法的时候,会调用当前类的实现

    private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
    for (Class<?> proxiedInterface : proxiedInterfaces) {
    Method[] methods = proxiedInterface.getDeclaredMethods();
    for (Method method : methods) {
    if (AopUtils.isEqualsMethod(method)) {
    this.equalsDefined = true;
    }
    if (AopUtils.isHashCodeMethod(method)) {
    this.hashCodeDefined = true;
    }
    if (this.equalsDefined && this.hashCodeDefined) {
    return;
    }
    }
    }
    }
  3. 调用 JDK 的 Proxy#newProxyInstance(..) 方法创建代理对象,入参的 InvocationHandler 实现了就是当前对象

对于上面 JDK 创建代理对象的过程是不是很熟悉,不清楚的小伙伴可以查看我前面 《初识 JDK、CGLIB 两种动态代理》 这篇文章

AopProxyUtils

org.springframework.aop.framework.AopProxyUtils 工具类,获取 JDK 创建代理对象时需要实现哪些接口,如下:

static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
// <1> 获取需要代理的接口(目标类实现的接口),放入 `specifiedInterfaces` 中
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
if (specifiedInterfaces.length == 0) {
// No user-specified interfaces: check whether target class is an interface.
Class<?> targetClass = advised.getTargetClass();
if (targetClass != null) {
if (targetClass.isInterface()) {
advised.setInterfaces(targetClass);
}
else if (Proxy.isProxyClass(targetClass)) {
advised.setInterfaces(targetClass.getInterfaces());
}
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
// <2> 判断目标类实现的接口是否存在 SpringProxy|Advised|DecoratingProxy 接口,不存在需要添加一个
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
int nonUserIfcCount = 0;
if (addSpringProxy) {
nonUserIfcCount++;
}
if (addAdvised) {
nonUserIfcCount++;
}
if (addDecoratingProxy) {
nonUserIfcCount++;
}
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
int index = specifiedInterfaces.length;
// <3> 如果目标类实现的接口没有 SpringProxy,则添加一个
// 这样创建的代理对象就会实现这个接口,就能知道这个代理对象是否由 Spring 创建
if (addSpringProxy) {
proxiedInterfaces[index] = SpringProxy.class;
index++;
}
// 添加一个 Advised 接口
if (addAdvised) {
proxiedInterfaces[index] = Advised.class;
index++;
}
// 添加一个 DecoratingProxy 接口
if (addDecoratingProxy) {
proxiedInterfaces[index] = DecoratingProxy.class;
}
// <4> 返回需要代理的接口
return proxiedInterfaces;
}

该方法的处理过程如下:

  1. 获取需要代理的接口(目标类实现的接口),放入 specifiedInterfaces
  2. 判断目标类实现的接口是否存在 SpringProxy|Advised|DecoratingProxy 接口,不存在需要添加一个
  3. 通常情况下,上面三个接口都会添加到 specifiedInterfaces 的后面
  4. 返回 specifiedInterfaces 数组

通过上面这个方法得到的结论:在 Spring 内部通过 JDK 创建的代理对象会实现额外的接口,包括 SpringProxy 标记接口,可区分代理对象是否为 Spring 创建的

4 CglibAopProxy

org.springframework.aop.framework.CglibAopProxy,CGLIB 动态代理类,可创建代理对象

CGLIB 动态代理比 JDK 动态代理可要复杂得多~

构造函数

class CglibAopProxy implements AopProxy, Serializable {

	// Constants for CGLIB callback array indices
// 因为 CGLIB 设置的 Callback 是一个数组,下面定义了数组中固定几个拦截器的位置
// 进行 AOP 代理的通用拦截器
private static final int AOP_PROXY = 0;
// 执行目标方法的拦截器
private static final int INVOKE_TARGET = 1;
// 空的 Callback 对象,对于 finalize() 方法,不需要进行任何处理
private static final int NO_OVERRIDE = 2;
// 目标对象调度器,用于获取目标对象
private static final int DISPATCH_TARGET = 3;
// 配置管理器的调度器,会返回一个 AdvisedSupport 对象
private static final int DISPATCH_ADVISED = 4;
// 处理 `equals(Object)` 方法的拦截器
private static final int INVOKE_EQUALS = 5;
// 处理 `hashCode()` 方法的拦截器
private static final int INVOKE_HASHCODE = 6; /** Logger available to subclasses; static to optimize serialization. */
protected static final Log logger = LogFactory.getLog(CglibAopProxy.class); /** Keeps track of the Classes that we have validated for final methods. */
private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<>(); /** 代理对象的配置信息,例如保存了 TargetSource 目标类来源、能够应用于目标类的所有 Advisor */
protected final AdvisedSupport advised; /** 创建代理对象的构造方法入参 */
@Nullable
protected Object[] constructorArgs; /** 创建代理对象的构造方法的入参类型 */
@Nullable
protected Class<?>[] constructorArgTypes; /** Dispatcher used for methods on Advised. 配置管理器的调度器,会返回一个 AdvisedSupport 对象 */
private final transient AdvisedDispatcher advisedDispatcher; /**
* 缓存方法的调用器数组索引
* key:方法名称
* value:方法对应的方法调用器在 Callback 数组中的位置
*/
private transient Map<String, Integer> fixedInterceptorMap = Collections.emptyMap(); // 方法调用器在 Callback 数组中的偏移量
private transient int fixedInterceptorOffset; public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 // 没有 Advisor,表示没有任何动作
&& config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) // 没有来源
{
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}
}

上面的每一个属性都有注释,都非常重要,在 Spring 的 CGLIB 动态代理创建代理对象时,会设置一个 Callback 数组,上面定义了数组中固定几个拦截器的位置

数组中前面的几个 Callback 如下:

  • 0:进行 AOP 代理的通用拦截器【重点关注】
  • 1:执行目标方法的拦截器
  • 2:空的 Callback 对象,例如 finalize() 方法,不需要进行任何处理
  • 3:目标对象调度器,用于获取目标对象
  • 4:配置管理器的调度器,会返回一个 AdvisedSupport 对象
  • 5:处理 equals(Object) 方法的拦截器
  • 6:处理 hashCode() 方法的拦截器

4.1 getProxy 方法

getProxy() 方法,获取一个 CGLIB 动态代理对象,如下:

@Override
public Object getProxy() { return getProxy(null); } @Override
public Object getProxy(@Nullable ClassLoader classLoader) {
try {
// <1> 获取目标类
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); // <2> 将目标类作为被代理的类
Class<?> proxySuperClass = rootClass;
// <3> 如果目标类已经被 CGLIB 提升(名称包含 `$$` 符号)
if (ClassUtils.isCglibProxyClass(rootClass)) {
// <3.1> 获取目标类的父类作为被代理的类
proxySuperClass = rootClass.getSuperclass();
// <3.2> 获取目标类实现的接口,并添加至当前 AdvisedSupport 配置管理器中
// 例如 `@Configuration` 注解的 Bean 会被 CGLIB 提升,实现了 EnhancedConfiguration 接口
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
} // Validate the class, writing log messages as necessary.
// <4> 进行校验,仅打印日志,例如 final 修饰的方法不能被 CGLIB 提升
validateClassIfNecessary(proxySuperClass, classLoader); // Configure CGLIB Enhancer...
// <5> 创建 CGLIB 的增强类,并进行接下来的配置
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
// `useCache` 默认为 `true`,可通过 `cglib.useCache` 系统参数指定
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// <5.1> 设置被代理的类
enhancer.setSuperclass(proxySuperClass);
// <5.2> 设置需要代理的接口(可能没有,不过都会加上 Spring 内部的几个接口,例如 SpringProxy)
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
// <5.3> 设置命名策略,默认生成的代理对象的名称中包含 '$$' 和 'BySpringCGLIB'
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); // <5.4> 获取回调接口,也就是 MethodInterceptor 方法拦截器
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
// <5.5> 设置 Callback 过滤器,用于筛选出方法对应的 Callback 回调接口
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance.
// <6> 创建代理对象,CGLIG 字节码替身,创建目标类的子类
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
// 抛出 AopConfigException 异常
}
catch (Throwable ex) {
// 抛出 AopConfigException 异常
}
}

该方法的处理过程如下:

  1. 获取目标类 rootClass
  2. 将目标类作为被代理的类 proxySuperClass
  3. 如果目标类已经被 CGLIB 提升(名称包含 $$ 符号)
    1. 获取目标类的父类作为被代理的类
    2. 获取目标类实现的接口,并添加至当前 AdvisedSupport 配置管理器中,例如 @Configuration 注解的 Bean 会被 CGLIB 提升,实现了 EnhancedConfiguration 接口
  4. 进行校验,仅打印日志,例如 final 修饰的方法不能被 CGLIB 提升
  5. 创建 CGLIB 的增强类 Enhancer 对象,并进行接下来的配置
    1. 设置被代理的类为 proxySuperClass
    2. 设置需要代理的接口(例如 SpringProxy),在前面讲述 JDK 动态代理创建代理对象时已经讲过 AopProxyUtils 这个工具类,不同的是 CGLIB 不会添加 DecoratingProxy 这个接口
    3. 设置命名策略,默认生成的代理对象的名称中包含 $$BySpringCGLIB
    4. 调用 getCallbacks(Class<?>) 方法,获取回调数组 Callback[] callbacks,也就是 MethodInterceptor 方法拦截器
    5. 设置 Callback 过滤器为 ProxyCallbackFilter,用于筛选出方法使用 callbacks 中的哪个 Callback
  6. 调用 createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) 方法,创建代理对象,并返回

CGLIB 创建代理对象的过程整体上并不复杂,其中第 5.45.56 步我们接下来逐步分析

4.2 getCallbacks 方法

getCallbacks(Class<?> rootClass) 方法,获取代理对象的 Callback 回调数组,如下:

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
// <1> 获取代理对象的三个配置信息
// `exposeProxy` 是否暴露代理对象,通常为 `false`
boolean exposeProxy = this.advised.isExposeProxy();
// `isFrozen` 配置管理器是否被冻结,通常为 `false`
boolean isFrozen = this.advised.isFrozen();
// `isStatic` 是否是静态的目标对象,也就是说目标对象是否每次都需要创建,通常为 `true`
boolean isStatic = this.advised.getTargetSource().isStatic(); // Choose an "aop" interceptor (used for AOP calls).
// <2> 【重点】创建目标对象的拦截器,MethodInterceptor 方法拦截器,会对目标对象的方法进行拦截处理,之前筛选出来的 Advisor 会在这个里面被调用
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); // Choose a "straight to target" interceptor. (used for calls that are
// unadvised but can return this). May be required to expose the proxy.
// <3> 创建目标对象的执行器,用于执行目标方法
Callback targetInterceptor;
// <3.1> 如果需要暴露当前代理对象,则通过 AopContext 进行暴露,放入 ThreadLocal 中,其他的和下面都相同
if (exposeProxy) {
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
// <3.2> 否则,不暴露
else {
targetInterceptor = (isStatic ?
// <3.2.1> 用于执行方法代理对象,并对最终的返回结果进一步处理(返回结果是否需要为代理对象,返回结果是否不能为空)
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
// <3.2.2> 和上者的区别就是,每次拦截都会重新获取目标对象,结束后释放该目标对象
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
} // Choose a "direct to target" dispatcher (used for
// unadvised calls to static targets that cannot return this).
// <4> 目标对象调度器,用于获取目标对象
Callback targetDispatcher = (isStatic ?
// <4.1> 目标对象的调度器,用于获取当前目标对象
new StaticDispatcher(this.advised.getTargetSource().getTarget()) :
// <4.2> 目标对象的调度器,空的 Callback,不做任何处理
new SerializableNoOp()); // <5> 生成主要的几个回调接口,也就是上面创建的几个 Callback,放入 `mainCallbacks` 数组
Callback[] mainCallbacks = new Callback[] {
// 0:进行 AOP 代理的通用拦截器
aopInterceptor, // for normal advice
// 1:执行目标方法的拦截器
targetInterceptor, // invoke target without considering advice, if optimized
// 2:空的 Callback 对象,例如 `finalize()` 方法,不需要进行任何处理
new SerializableNoOp(), // no override for methods mapped to this
// 3:目标对象调度器,用于获取目标对象
targetDispatcher,
// 4:配置管理器的调度器,会返回一个 AdvisedSupport 对象
// 因为代理对象会实现 Advised 接口,拦截到其里面的方法时,需要调用当前 AdvisedSupport 的方法
this.advisedDispatcher,
// 5:处理 `equals(Object)` 方法的拦截器
new EqualsInterceptor(this.advised),
// 6:处理 `hashCode()` 方法的拦截器
new HashCodeInterceptor(this.advised)
}; Callback[] callbacks; // If the target is a static one and the advice chain is frozen,
// then we can make some optimizations by sending the AOP calls
// direct to the target using the fixed chain for that method.
/*
* <6> 如果目标对象不需要每次都创建,且当前 AdvisedSupport 配置管理器被冻结了,性能优化,可暂时忽略
* 那么在创建代理对象的时候,就可以先将目标对象的每个方法对应的方法调用器解析出来,该过程有点性能损耗,这样在代理对象执行方法的时候性能有所提升
* 不过由于这里会解析出许多方法调用器,会占有一定的内存,以空间换时间
*/
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<>(methods.length); // TODO: small memory optimization here (can skip creation for methods with no advice)
/*
* <6.1> 遍历目标对象所有的方法
*/
for (int x = 0; x < methods.length; x++) {
Method method = methods[x];
// <6.1.1> 获取能够应用于该方法的所有拦截器(有序)
// 不同的 AspectJ 根据 @Order 排序
// 同一个 AspectJ 中的 Advice 排序:AspectJAfterThrowingAdvice > AfterReturningAdviceInterceptor > AspectJAfterAdvice > AspectJAroundAdvice > MethodBeforeAdviceInterceptor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
// <6.1.2> 创建一个方法调用器
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
// <6.1.3> 将每个方法的对应的调用器的位置索引缓存起来
this.fixedInterceptorMap.put(methods.toString(), x);
} // Now copy both the callbacks from mainCallbacks
// and fixedCallbacks into the callbacks array.
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
// <6.2> 将 `mainCallbacks` 复制到 `callbacks` 数组
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
// <6.3> 将 `fixedCallbacks` 复制到 `callbacks` 数组(拼接在后面)
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
// <6.4> 记录一个已生成的方法调用器的偏移量
this.fixedInterceptorOffset = mainCallbacks.length;
}
// <7> 否则,不进行解析,取上面的几个主要的 Callback
else {
callbacks = mainCallbacks;
}
// <8> 返回这个目标对象对应的 Callback 数组
return callbacks;
}

该方法的处理过程如下:

  1. 是获取代理对象的三个配置信息

    • exposeProxy 是否暴露代理对象,通常为 false
    • isFrozen 配置管理器是否被冻结,通常为 false
    • isStatic 是否是静态的目标对象,也就是说目标对象是否每次都需要创建,通常为 true
  2. 【重点】创建目标对象的拦截器,DynamicAdvisedInterceptor 方法拦截器,会对目标对象的方法进行拦截处理,代理对象的处理逻辑都在这里面完成

  3. 创建目标对象的执行器,用于执行目标方法

    1. 如果需要暴露当前代理对象,则通过 AopContext 进行暴露,放入 ThreadLocal 中,其他的和下面都相同
    2. 否则,不暴露
      1. isStatic 为 true,创建 StaticUnadvisedInterceptor 对象,用于执行方法代理对象,并对最终的返回结果进一步处理(返回结果是否需要为代理对象,返回结果是否不能为空)
      2. 否则,创建 DynamicUnadvisedInterceptor 对象,和上者的区别就是,每次拦截都会重新获取目标对象,结束后释放该目标对象
  4. 目标对象调度器,用于获取目标对象

    1. isStatic 为 true,创建 StaticDispatcher 对象,目标对象的调度器,用于获取当前目标对象
    2. 否则,创建 SerializableNoOp 对象,空的 Callback,不做任何处理
  5. 生成主要的几个回调接口,也就是上面创建的几个 Callback,放入 mainCallbacks 数组,可以回到上面的构造函数看看哦

    死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象的更多相关文章

    1. 白话Spring(基础篇)---AOP(execution表达式)

      作为AOP的最后一节内容,我们来简单总结一下切面表达式上见的书写方法.下面的那内容有参考其他博文,在此先对开源博客的各位大神表示感谢! -------------------------------- ...

    2. 白话Spring(基础篇)---AOP(execution表达式)(转)

      [一知半解,就是给自己挖坑] 作为AOP的最后一节内容,我们来简单总结一下切面表达式上见的书写方法.下面的那内容有参考其他博文,在此先对开源博客的各位大神表示感谢! ----------------- ...

    3. Spring第12篇—— Spring对Hibernate的SessionFactory的集成功能

      由于Spring和Hibernate处于不同的层次,Spring关心的是业务逻辑之间的组合关系,Spring提供了对他们的强大的管理能力, 而Hibernate完成了OR的映射,使开发人员不用再去关心 ...

    4. 死磕Spring之AOP篇 - Spring AOP常见面试题

      该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

    5. 死磕Spring之AOP篇 - Spring AOP总览

      该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

    6. 死磕Spring之AOP篇 - Spring AOP自动代理(一)入口

      该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

    7. 死磕Spring之AOP篇 - Spring AOP自动代理(二)筛选合适的通知器

      该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

    8. 死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理

      该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

    9. 死磕Spring之AOP篇 - Spring AOP注解驱动与XML配置

      该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

    随机推荐

    1. 小例子 熟悉jquery

      <div class="tab-head"> <h2 id="tab1" class="selected">JQGr ...

    2. 初学 react &vert; redux

      react | redux 一.安装 React Redux 依赖 React 0.14或更新版本 npm install --sava react-redux 你需要使用 npm 作为包管理工具,配 ...

    3. 我刚知道的WAP app中meta的属性&lpar;转载&rpar;

      之前我一直做的都是WEB前端开发,来北京以后面试了一个移动前端开发,WAP前端开发. 其实在原来公司的时候也做过这方面的开发,可面试的时候面试官问我,要想强制让文档与设备的宽度保持1:1,mate标签 ...

    4. DataTrigger的几个用法

      1.用在textbox等输入控件上,验证输入是否合法. <Window.Resources> <Style TargetType="TextBox"> &l ...

    5. THREE&period;js代码备份——canvas - lines - colors&lpar;希尔伯特曲线3D、用HSL设置线颜色&rpar;

      <!DOCTYPE html> <html lang="en"> <head> <title>three.js canvas - l ...

    6. C&num;-反射reflection

      目录 简介 引入 1.新建类库 2. 类库的使用 3.反射 反射实例1 反射实例2 反射实例3 C# shanzm 简介 反射(reflection)是什么? 在<精通C#>中是这么说的& ...

    7. navicat 和 pymysql

      ---------------------------------------------------相信时间的力量,单每月经过努力的时间,一切的安排都是懊脑的安排. # # ------------ ...

    8. 多线程实现Thread&period;Start&lpar;&rpar;与ThreadPool&period;QueueUserWorkItem两种方式对比

      Thread.Start(),ThreadPool.QueueUserWorkItem都是在实现多线程并行编程时常用的方法.两种方式有何异同点,而又该如何取舍? 写一个Demo,分别用两种方式实现.观 ...

    9. Tensorboard on Server

      ssh -L 6006:localhost:5001 username@ml.cs.tsinghua.edu.cn -p 4513 6006是本地端口 5001是远程tensorboard绑定的端口

    10. Python - Django - ORM 实例(二)

      在 app01/models.py 中添加 Book 类对象表 from django.db import models # Create your models here. # 出版社 class ...