• 轻轻松松看懂Spring AOP源码


    轻轻松松看懂Spring AOP源码

    https://baijiahao.baidu.com/s?id=1596466083334197175&wfr=spider&for=pc

    如果对spring的核心容器和JDK动态代理、CGLIB有所了解,接下来再看spring AOP源码会比较容易。文中所有代码片段截图对应的spring版本是5.0。

    本文内容曾首发于头条。

    首先来看个问题,spring在哪里使用了AOP?spring 实现AOP代码的源头在哪里?

    spring AOP运用动态代理技术来创建和初始化代理对象。至于AOP代码的源头和入口,自然是和加载代理类的BeanDefinition和代理对象的创建、初始化有关。

    1.spring AOP之加载和解析aop配置

    先来看下加载BeanDefinition以及对aop配置的解析,下面是从容器开始启动到解析BeanDefinitions的方法链:

    然后我们直接定位到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,如下图:

    上图中parseCustomElement是对非节点的解析,相关的节点解析自然是走178行代码分支。该分支实际调用的是下图中的代码片段:

    1361行代码根据nameSpace匹配相应的handler,aop节点匹配的是右图中的AopNamespaceHandler。1366行的parse调用的是其父类NamespaceHandlerSupport的parse方法,如下图:

    节点匹配的则是图中右侧的ConfigBeanDefinitionParser。来看下其实现:

    上述代码106行配置了用于创建代理对象的AspectJAwareAdvisorAutoProxyCreator,我们看完aop配置解析之后再来分析。

    节点的子节点是,所以这里走118行的分支。然后就是对的子节点,等的解析。

    读到这里应该对AOP配置的解析有了大概的认识。但是你是否想过,解析的结果封装在哪里了?是ParserContext。

    ConfigBeanDefinitionParser#parseAspect调用了ConfigBeanDefinitionParser#parseAdvice,来看下其实现:

    其中340行是最关键的,可以看到最终是通过创建RootBeanDefinition来封装我们aop节点的配置信息,然后在349行将beanDefinition注册到容器(BeanFactory)。

    aop配置的解析就看到这里。下面来看aop中代理对象的创建、实例化等。

    2.spring AOP之创建代理

    aop创建代理对象的时机是在调用getBean首次从容器中获取bean时。其实现

    AbstractBeanFactory#getBean(java.lang.String)调用的是AbstractBeanFactory#doGetBean,下面来看该方法:

    假设我们要获取的bean是单例并且是首次获取,那么真正创建bean是调用的312行的createBean方法。至此,我们来看一下整个方法链:

    下面来看下AbstractAutowireCapableBeanFactory#initializeBean:

    其中红线框起来的四个方法分别是:

    invokeAwareMethods:调用BeanNameAware.setBeanName, BeanFactoryAware.setBeanFactory等

    applyBeanPostProcessorsBeforeInitialization:调用BeanPostProcessor.postProcessBeforeInitialization

    invokeInitMethods:调用InitializingBean#afterPropertiesSet,调用自定义initMethod

    applyBeanPostProcessorsAfterInitialization:调用BeanPostProcessor#postProcessAfterInitialization

    之前提到在解析aop配置时向容器注册了AspectJAwareAdvisorAutoProxyCreator,那么此处这个类要派上用场了。我们先来看下这个类的继承体系:

    从顶层看,该类主要包含三部分:

    ProxyConfig即解析而来的aop配置

    Aware部分主要是使其可访问ClassLoader和BeanFactory

    BeanPostProcessor则是bean初始化的前置和后置

    上面出现的applyBeanPostProcessorsAfterInitialization调用的就是AspectJAwareAdvisorAutoProxyCreator的postProcessAfterInitialization,准确地说是其继承自父类的父类

    AbstractAutoProxyCreator.postProcessAfterInitialization。我们来看下该方法调用的

    AbstractAutoProxyCreator#wrapIfNecessary,这也是spring判断是否需要创建代理对象的地方:

    该方法主要分三步:

    352行判断该接口或类或方法是否与配置的pointcut的表达式匹配,匹配则需要创建代理对象,不匹配则无需代理。然后如果匹配则返回方法拦截器

    355行创建代理对象

    357行对代理类进行缓存

    我们重点看下createProxy方法实现,方法链如下:

    有了方法链之后我们直接跳到DefaultAopProxyFactory#createAopProxy,这个方法决定了spring aop动态代理是使用CGLIB还是JDK Proxy:

    解释下51行if语句中的三个条件:

    isOptimize表示让spring自行优化,默认为false

    isProxyTargetClass表示是否对类生成代理,默认为false(即使用JDK Proxy,只代理接口)

    第三个表示bean没有实现任何接口或者实现的接口是SpringProxy接口

    综上,spring AOP默认的创建代理的策略是:

    对接口生成代理使用JDK Proxy

    对类生成代理使用CGLIB

    可通过proxyTargetClass配置是否对类生成代理,为true表示对类生成代理,为false表示不会对类(没有实现SpringProxy以外的接口的类)生成代理

    如果觉得写的不错,记得,如果写的不好欢迎批评指正,让我们一起进步!

  • 相关阅读:
    C#可空类型 T?
    Unity踩过的坑
    Unity可视化数据:创建图表
    unity3d屏幕截图功能
    unity3d插入android有米广告
    Unity调用PC摄像头
    使用Unity的50个建议
    Unity3d流光效果
    unity3d中的Quaternion.LookRotation
    Unity3D中可重载虚函数的总结
  • 原文地址:https://www.cnblogs.com/handsome1013/p/11572845.html
Copyright © 2020-2023  润新知