Spring AOP源码解读1 - 程序入口

前言

最近看了《从零开始写JavaWeb框架》,想比较一下Spring AOP的实现方式和书的上实现方式有什么不同,所以先把Spring AOP的源码读一下,再进行比较。

Spring的源码实在是复杂,在读的过程中参考了很多书和网上的文章,本文算是这些文章的总结,再加上一些我自己对个别细节的理解。

本文分成 3 部分:

  • 程序入口
  • 切面和增强的取得
  • 代理的生成

一,注册AspectJAnnotationAutoProxyCreator

如果使用<aop:aspectj-autoproxy />标签来自动生成代理的话,入口程序是AopNamespaceHandler。在AopNamespaceHandler中,下面一段代码是对<aop:aspectj-autoproxy />标签执行的调用:

registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

AspectJAutoProxyBeanDefinitionParser解析器中,首先调用的parse方法。parse方法中有一行代码:

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);

我们看一下registerAspectJAnnotationAutoProxyCreatorIfNecessary方法的实际内容:

public static void registerAutoProxyCreatorIfNecessary(
    ParserContext parserContext, Element sourceElement) {
    // 注册或更新 AutoProxyCreator 定义 beanName 为 org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition
    // 如果internalAutoProxyCreator的BeanDefinition已经存在,而根据优先级更新BeanDefinition
    // 在这里我们注册的是AnnotationAwareAspectJAutoProxyCreator
    BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    // 对于 proxy-target-class 以及 expose-proxy 属性的处理
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    // 注册组件并通知,便于监听器作进一步处理
    // 其中 beanDefinition 的 className 为 AnnotationAwareAspectJAutoProxyCreator
    registerComponentIfNecessary(beanDefinition, parserContext);
}


问题1:那为什么注册AnnotationAwareAspectJAutoProxyCreator,注册AnnotationAwareAspectJAutoProxyCreator有什么用呢?

其实,实现AOP处理是其实是通过BeanPostProcessor机制实现的。AnnotationAwareAspectJAutoProxyCreator的父类也实现一个BeanPostProcessor类型的接口,而生成代理的逻辑就在AnnotationAwareAspectJAutoProxyCreator的BeanPostProcessor接口实现里面。
更严谨地说,AnnotationAwareAspectJAutoProxyCreator的父类实现的接口是
SmartInstantiationAwareBeanPostProcessor,主要是Spring框架内部使用的一个接口。而这个接口的父接口InstantiationAwareBeanPostProcessor 是实现代理的重点之一。

这3个接口的关系如下:
SmartInstantiationAwareBeanPostProcessor -> InstantiationAwareBeanPostProcessor -> BeanPostProcessor

问题2:为什么说是是InstantiationAwareBeanPostProcessor接口的子接口,接口是重点之一?那InstantiationAwareBeanPostProcessor接口是什么接口呢?

BeanPostProcessor主要作用于Bean实例化后,初始化前后。InstantiationAwareBeanPostProcessor虽然是BeanPostProcessor的子接口,但它的调用时间点其发生在Bean实例化前,在真正调用doCreate()创建bean实例之前。
在创建Bean实例之前,会先调用resolveBeforeInstantiation方法,这个方法是生成Bean代理的地方。如果此方法返回值不为空则直接返回生成的Bean的代理,如果为空就向下走正常的Bean生成流程。

spring注释“Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. ”给BeanPostProcessors一个机会返回代理proxy对象。

InstantiationAwareBeanPostProcessor接口方法,就是在resolveBeforeInstantiation方法中调用的。所以可以看出,BeanPostProcessor有很多,但Spring AOP的实现就是通过InstantiationAwareBeanPostProcessor这个BeanPostProcessor实现的。看一下源码:

protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
        throws BeanCreationException {
    ......
    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        // 如果返回值不为空,说明生成成了此BeanName的代理,直接返回代理对象
        Object bean = resolveBeforeInstantiation(beanName, mbd);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        ......
    }

    // 如果没有生成代理对象,就按正常流程走,生成Bean对象
    Object beanInstance = doCreateBean(beanName, mbd, args);
    .....
    return beanInstance;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 调用InstantiationAwareBeanPostProcessor接口的地方
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
            throws BeansException {

        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                // 转换成InstantiationAwareBeanPostProcessor接口,并调用
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

顺带说一下,注册AnnotationAwareAspectJAutoProxyCreator的目的是:把这个类的BeanDefinition通过registerBeanDefinition方法(DefaultListableBeanFactory类中)加入到beanDefinitionMap中,作为一个Bean让Spring管理,这样Spring就可以随意取得它了。


问题3:如果使用<aop:aspectj-autoproxy />标签来自动生成代理的话,入口程序是AopNamespaceHandler。那AopNamespaceHandler 是在什么地方被调用的呢?

这个问题让我们从容器启动的地方开始说明。以FileSystemXmlApplicationContext 为例,这个类的入口是构造函数里面的refresh() 方法。从refresh() 方法开始,调用流程是这样的:(以下流程全部是嵌套调用的关系)

1. refresh() ->
   刷新容器 
2. obtainFreshBeanFactory() ->
   获得刷新后的Bean容器
3. refreshBeanFactory() ->
   刷新Bean容器
4. loadBeanDefinitions() ->
   加载BeanDefinition
5. XmlBeanDefinitionReader#loadBeanDefinitions
   新建一个XmlBeanDefinitionReader实例(new XmlBeanDefinitionReader(beanFactory)),调用这个实例的loadBeanDefinitions方法。
6. XmlBeanDefinitionReader#doLoadBeanDefinitions
7. XmlBeanDefinitionReader#registerBeanDefinitions
8. XmlBeanDefinitionReader#createBeanDefinitionDocumentReader
   在这个方法中取得了DefaultBeanDefinitionDocumentReader实例。接下来调用这个实例的方法。
9. DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
   在这个方法中,根据URI判断是否使用AopNamespaceHandler
10. DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
   从registerBeanDefinitions方法开始,内部连续调用一系列方法,一直调用到parseBeanDefinitions方法。在这个方法中,根据XML文件的URI判断使用哪些解析器,例如是<Beans>类标签解析器,还是<aop>类标签解析器。
   如果是需要<aop>标签解析器的话,在this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)代码中,从配置文件(spring.handlers)从取出AopNamespaceHandler的类名,生成这个类的实例,然后调用这个类的parse方法。
11. AopNamespaceHandler#parse
   这个方法的功能是,根据具体标签调用具体解析器的parse方法。
   - <aop:aspectj-autoproxy>:AspectJAutoProxyBeanDefinitionParser
   - <aop:config>:ConfigBeanDefinitionParser
   等。
   这个方法的调用,又回到了我们最初讲的AopNamespaceHandler入口的地方。          

到此为止,从容器到AopNamespaceHandler类调用的过程也讲完了。

二,AspectJAnnotationAutoProxyCreator的处理流程

通过上面的内容,我们知道了注册AnnotationAwareAspectJAutoProxyCreator的意义,并且知道了生成代理是在它的BeanPostProcessor接口里做的,现在看看被实现的接口的内容。(postProcessAfterInitialization 具体实现是在其父类 AbstractAutoProxyCreator 中完成的):

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   if (bean != null) {
      // 根据给定的 bean 的 class 和 name 构建出个 key,格式:beanClassName_beanName
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         // 如果它适合被代理,则需要封装指定 bean。
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   // 是否已经处理过
   if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   // 无需增强
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   // 给定的 bean 类是否代表一个基础设施类,基础设施类不应代理,或者配置了指定 bean 不需要自动代理
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // 如果存在增强方法则创建代理(*重要*)
   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;
}

这里有两个方法特别重要:

  1. getAdvicesAndAdvisorsForBean:如果Bean是要被代理的对象的话,取得Bean相关的Interceptor
  2. createProxy:创建代理

下一篇文章,我们就这两个方法的下面的流程分开来分析一下,首先分析getAdvicesAndAdvisorsForBean相关代码。

关于接口实现的补充:

AnnotationAwareAspectJAutoProxyCreator 一共实现了2个BeanPostProcessor 的接口,的4个方法:

  • postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor)
  • postProcessAfterInstantiation(InstantiationAwareBeanPostProcessor)
  • postProcessBeforeInitialization(BeanPostProcessor)
  • postProcessAfterInitialization(BeanPostProcessor)

postProcessBeforeInstantiationInstantiationAwareBeanPostProcessor接口)方法中,这个方法是在AnnotationAwareAspectJAutoProxyCreator的基类AbstractAutoProxyCreator中实现的。细看一下,在postProcessAfterInitialization方法中也有类似的生成代理的代码。这是为什么呢?

上网找了一些资料,在postProcessBeforeInstantiation方法中有一个判断:

如果某个Bean设置了自定义TargetSource的话,就在本方法中进行生成代理

postProcessAfterInitialization则没有这样的判断,只是在生成代理前判断了一下代理是否已经生成。具体为什么有这样的必须还不清楚(以后有需要调查一下),但结果就是:

  • 如果Bean设置了自定义TargetSource,就在postProcessBeforeInstantiation中生成代理
  • 如果没有,就在postProcessAfterInitialization中生成代理。

最后,不管理在哪个方法里生成代理,在创建每个Bean时都会被调用这两个方法,代理的生成逻辑就是在这两个方法中实现的。

关于TargetSource:spring-aop组件详解——TargetSource目标源
关于自定义TargetSource:《Spring揭密》的9.6章节

参考:
Spring 源码分析(三) —— AOP(一)AOP原理:AOP系列一共6篇文章建议看看
Spring AOP源码分析(三)Spring AOP中的一些基本接口及其概念:这篇文章讲了AOP的接口,如果不明白接口的目的的话,理解AOP的代码有些困难,建议看看。
Spring AOP 简单模拟 :把Spring AOP的整个结构给简单化了,变成的容易明白

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值