AOP后置处理器

在这一章中,我们介绍了很多 AOP 原理的知识点,最后再对 AOP 后置处理器做一个说明,让 AOP 更加完整。

AnnotationAwareAspectJAutoProxyCreator方式

这个类有点长但比较重要,是 AOP 后置处理器,用于根据注解创建代理的默认类。在讲解之前,我们先看这个类的接口关系图,如图5.8所示。

image 2024 03 31 17 08 34 494
Figure 1. 图5.8 接口关系图

从图中可以看到,该类实现了 BeanPostProcessor 接口,而这个接口在介绍 IOC 时说过,它可以在 Bean 的前后做一些操作。因此 AnnotationAwareAspectJAutoProxyCreator 在实现这个接口之后,也一样可以对 Bean 进行增强。

那么它是怎么增强的?我们织入 AnnotationAwareAspectJAutoProxyCreator 后,看它是否实现 BeanPostProcessor 的方法,如果没有,继续向父类找,直到找到如上图的 AbstractAutoProxyCreator 类。代码如下所示。

public Object postProcessBeforeInitialization(Object bean, String beanName) {
   return bean;
}

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
   if (bean != null) {
          Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
          return this.wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

在上面的代码中,postProcessBeforeInitialization 只是返回了 Dean,但是 after 的方法是我们关注的重点。在 after 的注释上有如下的一段话。

/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/

这段话可以理解为,如果 Dean 是子类标识的,那么就用配置拦截器创建代理。那么如何把代理创建出来?我们再看 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(be an.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;
}

从上面的代码中可以看到 createProxy 方法,就是用于创建代理。需 Dean 的 Class、beaname、通知器数组、单例 Bean。如果继续使用 createProxy 方法,就会看到这一行代码。

ProxyFactory proxyFactory = new ProxyFactory();

在上文我们可以看到,重点是实现了后置处理器接口,所以这个类被称为 AOP 后置处理器。

后置处理器的注册

AbstractApplicationContext 中的 refresh 是 Spring 的核心方法,代理逻辑把这里作为入口,后置处理器的注册也是从这里进行的。代码如下所示。

public void refresh() throws BeansException, IllegalStateException {
   Object var1 = this.startupShutdownMonitor;
   synchronized(this.startupShutdownMonitor) {
//刷新准备应用上下文
      this.prepareRefresh();
//根据配置文件生成Bean
          ConfigurableListableBeanFactory beanFactory = this. obtainFreshBeanFactory();
//在上下文中使用Bean
      this.prepareBeanFactory(beanFactory);
      try {
//设置BeanFactory的后置处理器
          this.postProcessBeanFactory(beanFactory);
//调用BeanFactory的后置处理器
          this.invokeBeanFactoryPostProcessors(beanFactory);
//注册后置处理器
          this.registerBeanPostProcessors(beanFactory);
//对上下文的消息源进行初始化
          this.initMessageSource();
//初始化上下文中的事件机制
          this.initApplicationEventMulticaster();
//初始化其他的特殊Bean
          this.onRefresh();
//检查监听Bean并且将这些Bean向容器注册
          this.registerListeners();
//初始化
          this.finishBeanFactoryInitialization(beanFactory);
//发布容器事件,结束refresh过程
          this.finishRefresh();
      } catch (BeansException var9) {
          if (this.logger.isWarnEnabled()) {
               this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
          }
//销毁已经在前面过程中生成的单例Bean
          this.destroyBeans();
          this.cancelRefresh(var9);
          throw var9;
      } finally {
          this.resetCommonCaches();
      }
   }
}

在上面可以看到加粗的代码,就是在注册后置处理器。

后置处理器处理@Aspect的Bean

在5.1节的实例中,我们对切面添加 @Aspect 注解,然后添加 @Component 注解。因此在加载的时候,就会调用 getBean 方法,并且会执行 AbstractAutowireCapableBeanFactory 类中的 createBean 方法。我们看下面这段代码。

protected Object createBean(String beanName, RootBeanDefinition mbd,@Nullable Object[] args)throws BeanCreationException {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDefinition mbdToUse = mbd;
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd. getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }
   // Prepare method overrides.
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse. getResourceDescription(),
          beanName, "Validation of method overrides failed", ex);
   }
   try {
      // Give BeanPostProcessors a chance to return a proxy instead
of the target bean instance.
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
        return bean;
      }
   }
……
}

在加粗的代码处,会最终返回一个代理。关于 resolveBeforeInstantiation 方法的处理步骤还有很多,这里不再叙述,读者可以通过一段代码设置断点进行跟踪。