您的位置 首页 java

Spring源码:用于创建 AOP 代理的后处理器分析

概述

前面两篇文章分析了在注解配置和 XML 配置的情况下, Spring 是如何开启 AOP 特性的,经过源码分析我们知道,这两种方式的 AOP 开启,本质上都是注册了一个用来创建 AOP 代理的后处理器。

对于在 XML 中配置切面的情况,Spring 会把创建代理的工作交给 AspectJAwareAdvisorAutoProxyCreator 后处理器来处理,而对于通过注解配置切面的情况,则交由 Annotation AwareAspectJAutoProxyCreator 后处理器处理。

在本文章,将对这两个后处理器进行分析,了解他们大致的工作原理。

继承关系

AspectJAwareAdvisorAutoProxyCreator 和 AnnotationAwareAspectJAutoProxyCreator 两个后处理器的继承关系,在前两篇文章中已经了解过了,这里我们再做简单的回顾。

从上图中可以知道,这两个类是直接继承的父子类,他们有很多共同继承的类和实现的接口,可以推测出他们的工作逻辑有很大一部分是相同的。

由于他们是作为后处理器注册到 Spring 容器中的,因此,他们完成 AOP 代理创建的逻辑,一定是在后处理器的方法中。从上图中看到,他们共实现了三个后处理器的接口,接下来,我们再看这三个接口中定义的方法。

实现接口

先看看这三个接口都定义了哪些方法。

既然后处理器的作用要生成一个代理对象,那么,我们就应该去分析后处理器中可以修改被处理的 Bean 对象的处理方法,再上图中罗列的方法中有以下这些:

  • postProcessBeforeInstantiation方法可以在 Spring 实例化 Bean 对象之前,创建一个 Bean 对象。
  • postProcessBefore Initialization 方法可以在 Bean 的初始化方法被执行前,修改 Bean 对象。
  • postProcessAfterInitialization方法可以在 Bean 的初始化方法被执行前,修改 Bean 对象。

以上三个方法,都可能在执行的过程中,将当前的 Bean 对象,修改为新创建的代理对象。因此,接下来,我们需要从两个后处理器中找到这三个方法的实现逻辑。

不过,在源码中可以发现,这两个后处理器的后处理方法,都是在它们共同的父类 Abstract AutoProxyCreator 中实现的,所以,我们之后只需要分析 AbstractAutoProxyCreator 类中实现的处理方法就行了。并且,postProcessBeforeInitialization方法的实现是一个没有任何处理逻辑的默认实现,我们接下来从postProcessBeforeInstantiation和postProcessAfterInitialization两个方法中分析自动创建代理的逻辑。

代理创建的原理

下面从 AbstractAutoProxyCreator 的源码中,找到这两个方法进行分析。

postProcessBeforeInstantiation

先看postProcessBeforeInstantiation方法

 @Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
   Object cacheKey = getCacheKey(beanClass, beanName);

    if  (!StringUtils.hasLength(beanName) || !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.
   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;
}
复制代码  

方法的核心是后半部分的if语句块,在if语句块之前,通过getCustomTargetSource获取了当前 Bean 对象的自定义 TargetSource。TargetSource 指的是,Spring 创建的代理在调用目标方法时候要查找的目标来源,在创建代理对象时,当前的 Bean 对象,会被封装成一个 TargetSource 交给代理类,用于找到被增强的对象本身。

通常情况下,我们不会自定义 TargetSource,因此,这个方法并不是我们要找的创建代理的地方。

postProcessAfterInitialization

接下来,找到postProcessAfterInitialization方法。

 @Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}
复制代码  

这个方法是在 Bean 实例被执行初始化操作后被调用的,因此方法可以通过参数拿到 Bean 实例对象本身,以及 Bean 的名称。

首先,确保了 Bean 不为空之后,通过getCacheKey方法获得了一个缓存 Key。这个方法在刚刚的postProcessBeforeInstantiation方法中也见过,我们来看一下这个方法。

 protected Object getCacheKey(Class<?> beanClass, @Nullable String beanName) {
   if (StringUtils.hasLength(beanName)) {
      return (FactoryBean.class.isAssignableFrom(beanClass) ?
            BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
   }
   else {
      return beanClass;
   }
}
复制代码  

方法中判断了 Bean 的名称是否为空,如果不为空,则根据当前的 Bean 是不是一个 FactoryBean 来返回带或者不带工厂前缀的 Bean 名称,如果 Bean 的名称为空,则直接返回 Bean 得类型本身。

这个方法的目的是获得一个 缓存 Key,用于 AbstractAutoProxyCreator 中的缓存容器。

回到postProcessAfterInitialization方法中,接着,从earlyProxyReferences集合中,移除当前 Bean 对象对应的缓存 Key 保存的内容。那这个集合中存放了什么呢?在 AbstractAutoProxyCreator 源码中,除了这里,只有一处操作了earlyProxyReferences集合,而且是put操作,在另外一个方法中。

 @Override
public Object getEarlyBeanReference(Object bean, String beanName) {
   Object cacheKey = getCacheKey(bean.getClass(), beanName);
   this.earlyProxyReferences.put(cacheKey, bean);
   return wrapIfNecessary(bean, beanName, cacheKey);
}
复制代码  

这其实也是一个后处理器方法,之所以在寻找创建代理逻辑的时候没有考虑这个方法,是因为这个方法是在获取早期 Bean 对象的时候被调用的,也就是说,它不一定会被调用,而且调用的时机也不确定。在方法中,通过缓存 Key 向earlyProxyReferences集合中存放了早期的代理引用,方法最后返回了调用wrapIfNecessary方法的结果,这个方法我们稍后介绍。

再次回到postProcessBeforeInstantiation中,如果从earlyProxyReferences移除的内容,并不是 Bean 本身,则执行wrapIfNecessary方法并将结果作为后处理方法的结果返回。

wrapIfNecessary 方法

到这里,我们就需要看wrapIfNecessary方法,从名字就可以看出,它的作用是在必要的时候,对 Bean 对象进行包装,并且包装好的结果会作为容器中 Bean 的对象。因此,这个方法就是用来创建 Bean 对象代理的方法。

 // org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // Create proxy if we have advice.
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }

   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}
复制代码  

在判断了一些不需要在此处进行包装处理的情况后,进入了创建代理的逻辑,根据需不需要增强处理,返回创建好的代理对象,或者原本的 Bean 对象本身。

这部分逻辑,放到之后的文章来分析。

总结

本文分析了用于创建 AOP 代理对象的后处理器,主要是 AbstractAutoProxyCreator 类中的后处理方法。从它实现的后处理器接口中定义的方法中,找到了用于创建 AOP 代理的逻辑是在postProcessBeforeInstantiation方法中,也就是 AOP 代理是 Bean 执行完初始化逻辑之后创建的。

文章来源:智云一二三科技

文章标题:Spring源码:用于创建 AOP 代理的后处理器分析

文章地址:https://www.zhihuclub.com/174501.shtml

关于作者: 智云科技

热门文章

网站地图