12. 把AOP拓展到Bean的生命周期

工程结构

lqf-spring-step-12
├── main
│   ├── java
│   │   └── lqf
│   │       └── springframework
│   │           ├── aop
│   │           │   ├── AdvisedSupport.java
│   │           │   ├── Advisor.java
│   │           │   ├── BeforeAdvice.java
│   │           │   ├── ClassFilter.java
│   │           │   ├── MethodBeforeAdvice.java
│   │           │   ├── MethodMatcher.java
│   │           │   ├── Pointcut.java
│   │           │   ├── PointcutAdvisor.java
│   │           │   ├── TargetSource.java
│   │           │   ├── aspectj
│   │           │   │   ├── AspectJExpressionPointcut.java
│   │           │   │   └── AspectJExpressionPointcutAdvisor.java
│   │           │   └── framework
│   │           │       ├── AopProxy.java
│   │           │       ├── Cglib2AopProxy.java
│   │           │       ├── JdkDynamicAopProxy.java
│   │           │       ├── ProxyFactory.java
│   │           │       ├── ReflectiveMethodInvocation.java
│   │           │       ├── adapter
│   │           │       │   └── MethodBeforeAdviceInterceptor.java
│   │           │       └── autoproxy
│   │           │           └── DefaultAdvisorAutoProxyCreator.java
│   │           ├── beans
│   │           │   ├── BeansException.java
│   │           │   ├── PropertyValue.java
│   │           │   ├── PropertyValues.java
│   │           │   └── factory
│   │           │       ├── Aware.java
│   │           │       ├── BeanClassLoaderAware.java
│   │           │       ├── BeanFactory.java
│   │           │       ├── BeanFactoryAware.java
│   │           │       ├── BeanNameAware.java
│   │           │       ├── ConfigurableListableBeanFactory.java
│   │           │       ├── DisposableBean.java
│   │           │       ├── FactoryBean.java
│   │           │       ├── HierarchicalBeanFactory.java
│   │           │       ├── InitializingBean.java
│   │           │       ├── ListableBeanFactory.java
│   │           │       ├── config
│   │           │       │   ├── AutowireCapableBeanFactory.java
│   │           │       │   ├── BeanDefinition.java
│   │           │       │   ├── BeanFactoryPostProcessor.java
│   │           │       │   ├── BeanPostProcessor.java
│   │           │       │   ├── BeanReference.java
│   │           │       │   ├── ConfigurableBeanFactory.java
│   │           │       │   ├── InstantiationAwareBeanPostProcessor.java
│   │           │       │   └── SingletonBeanRegistry.java
│   │           │       ├── support
│   │           │       │   ├── AbstractAutowireCapableBeanFactory.java
│   │           │       │   ├── AbstractBeanDefinitionReader.java
│   │           │       │   ├── AbstractBeanFactory.java
│   │           │       │   ├── BeanDefinitionReader.java
│   │           │       │   ├── BeanDefinitionRegistry.java
│   │           │       │   ├── CglibSubclassingInstantiationStrategy.java
│   │           │       │   ├── DefaultListableBeanFactory.java
│   │           │       │   ├── DefaultSingletonBeanRegistry.java
│   │           │       │   ├── DisposableBeanAdapter.java
│   │           │       │   ├── FactoryBeanRegistrySupport.java
│   │           │       │   ├── InstantiationStrategy.java
│   │           │       │   └── SimpleInstantiationStrategy.java
│   │           │       └── xml
│   │           │           └── XmlBeanDefinitionReader.java
│   │           ├── context
│   │           │   ├── ApplicationContext.java
│   │           │   ├── ApplicationContextAware.java
│   │           │   ├── ApplicationEvent.java
│   │           │   ├── ApplicationEventPublisher.java
│   │           │   ├── ApplicationListener.java
│   │           │   ├── ConfigurableApplicationContext.java
│   │           │   ├── event
│   │           │   │   ├── AbstractApplicationEventMulticaster.java
│   │           │   │   ├── ApplicationContextEvent.java
│   │           │   │   ├── ApplicationEventMulticaster.java
│   │           │   │   ├── ContextClosedEvent.java
│   │           │   │   ├── ContextRefreshedEvent.java
│   │           │   │   └── SimpleApplicationEventMulticaster.java
│   │           │   └── support
│   │           │       ├── AbstractApplicationContext.java
│   │           │       ├── AbstractRefreshableApplicationContext.java
│   │           │       ├── AbstractXmlApplicationContext.java
│   │           │       ├── ApplicationContextAwareProcessor.java
│   │           │       └── ClassPathXmlApplicationContext.java
│   │           ├── core
│   │           │   └── io
│   │           │       ├── ClassPathResource.java
│   │           │       ├── DefaultResourceLoader.java
│   │           │       ├── FileSystemResource.java
│   │           │       ├── Resource.java
│   │           │       ├── ResourceLoader.java
│   │           │       └── UrlResource.java
│   │           └── util
│   │               └── ClassUtils.java
│   └── resources
└── test
    ├── java
    │   └── lqf
    │       └── springframework
    │           ├── SpringTest.java
    │           └── service
    │               ├── IUserService.java
    │               ├── UserService.java
    │               ├── UserServiceBeforeAdvice.java
    │               └── UserServiceInterceptor.java
    └── resources
        ├── important.properties
        ├── spring.xml
        └── springPostProcessor.xml

AOP 动态代理融入到Bean的生命周期中类关系,如图:

  • 整个类关系图中可以看到,在以 BeanPostProcessor 接口实现继承的 InstantiationAwareBeanPostProcessor 接口后,做了一个自动代理创建的类
    DefaultAdvisorAutoProxyCreator,这个类的就是用于处理整个 AOP 代理融入到 Bean 生命周期中的核心类。
  • DefaultAdvisorAutoProxyCreator 会依赖于拦截器、代理工厂和Pointcut与Advisor的包装服务
    AspectJExpressionPointcutAdvisor,由它提供切面、拦截方法和表达式。
  • Spring 的 AOP 把 Advice 细化了 BeforeAdvice、AfterAdvice、AfterReturningAdvice、ThrowsAdvice,目前我们做的测试案例中只用到了
    BeforeAdvice,这部分可以对照 Spring 的源码进行补充测试。

设计

在有了AOP的核心功能实现后,把这部分功能服务融入到 Spring 其实也不难,只不过要解决几个问题,包括:怎么借着 BeanPostProcessor
把动态代理融入到 Bean 的生命周期中,以及如何组装各项切点、拦截、前置的功能和适配对应的代理器。整体设计结构如下图:

  • 为了可以让对象创建过程中,能把xml中配置的代理对象也就是切面的一些类对象实例化,就需要用到 BeanPostProcessor
    提供的方法,因为这个类的中的方法可以分别作用与 Bean 对象执行初始化前后修改 Bean 的对象的扩展信息。但这里需要集合于
    BeanPostProcessor 实现新的接口和实现类,这样才能定向获取对应的类信息。
  • 但因为创建的是代理对象不是之前流程里的普通对象,所以我们需要前置于其他对象的创建,所以在实际开发的过程中,需要在
    AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。
  • 这里还包括要解决方法拦截器的具体功能,提供一些 BeforeAdvice、AfterAdvice
    的实现,让用户可以更简化的使用切面功能。除此之外还包括需要包装切面表达式以及拦截方法的整合,以及提供不同类型的代理方式的代理工厂,来包装切面服务。

实现

定义 Advice 拦截器链

源码1: lqf.springframework.aop.BeforeAdvice
源码2: lqf.springframework.aop.MethodBeforeAdvice

  • 在 Spring 框架中,Advice 都是通过方法拦截器 MethodInterceptor 实现的。环绕 Advice 类似一个拦截器的链路,Before
    Advice、After advice等,不过暂时我们需要那么多就只定义了一个 MethodBeforeAdvice 的接口定义。

定义 Advisor 访问者

源码1: lqf.springframework.aop.Advisor
源码2: lqf.springframework.aop.PointcutAdvisor

  • PointcutAdvisor 承担了 Pointcut 和 Advice 的组合,Pointcut 用于获取 JoinPoint,而 Advice 决定于 JoinPoint 执行什么操作。

源码3: lqf.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor

  • AspectJExpressionPointcutAdvisor 实现了 PointcutAdvisor 接口,把切面 pointcut、拦截方法 advice 和具体的拦截表达式包装在一起。这样就可以在
    xml 的配置中定义一个 pointcutAdvisor 切面拦截器了。

方法拦截器

源码: lqf.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor

  • MethodBeforeAdviceInterceptor 实现了 MethodInterceptor 接口,在 invoke 方法中调用 advice 中的 before 方法,传入对应的参数信息。
  • 而这个 advice.before 则是用于自己实现 MethodBeforeAdvice 接口后做的相应处理。

代理工厂

源码: lqf.springframework.aop.framework.ProxyFactory

  • 代理工厂主要解决的是关于 JDK 和 Cglib 两种代理的选择问题,有了代理工厂就可以按照不同的创建需求进行控制。

融入Bean生命周期的自动代理创建者

源码: lqf.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator

  • DefaultAdvisorAutoProxyCreator 类的主要核心实现在于 postProcessBeforeInstantiation 方法中,从通过
    beanFactory.getBeansOfType 获取 AspectJExpressionPointcutAdvisor 开始。
  • 获取了 advisors 以后就可以遍历相应的 AspectJExpressionPointcutAdvisor 填充对应的属性信息,包括:目标对象、拦截方法、匹配器,之后返回代理对象即可。
  • 现在调用方获取到的这个 Bean 对象就是一个已经被切面注入的对象了,当调用方法的时候,则会被按需拦截,处理用户需要的信息。

融入到Bean的生命周期

源码: lqf.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

  • 因为创建的是代理对象不是之前流程里的普通对象,所以我们需要前置于其他对象的创建,即需要在
    AbstractAutowireCapableBeanFactory#createBean 优先完成 Bean 对象的判断,是否需要代理,有则直接返回代理对象。

总结

  • 本章节实现 AOP 功能的外在体现主要是把以前自己在单元测试中的切面拦截,交给 Spring 的 xml 配置了,也就不需要自己手动处理了。
  • 一个功能的实现往往包括核心部分、组装部分、链接部分,为了这些各自职责的分工,则需要创建接口和类,由不同关系的继承、实现进行组装。
  • 目前实现的 AOP 与 Spring 源码中的核心逻辑是类似的,但更会偏简单一些,也不会考虑更多的复杂场景遇到的问题,包括是否有构造函数、是否为代理中的切面等。

返回目录