Spring AOP源码透析

* AOP原理:【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】

 *     @EnableAspectJAutoProxy;核心从这个入手,AOP整个功能要启作用,就是靠这个,加入它才有AOP

       跟进@EnableAspectJAutoProxy源码:

//导入了此类,点进去看

@Import(AspectJAutoProxyRegistrar.class)

public @interface EnableAspectJAutoProxy {

    //proxyTargetClass属性,默认false,采用JDK动态代理织入增强(实现接口的方式);如果设为true,则采用CGLIB动态代理织入增强

   boolean proxyTargetClass() default false;

    //通过aop框架暴露该代理对象,aopContext能够访问

   boolean exposeProxy() default false;

}

它引入AspectJAutoProxyRegistrar, 并实现了ImportBeanDefinitionRegistrar接口

ImportBeanDefinitionRegistrar接口作用: 能给容器中自定义注册组件, 以前也使用过, 比如我们以前也使用过这个类

 

AspectJAutoProxyRegistrar里可以自定义注册一些bean

那么注册了什么bean呢? 以debug模式进行测试一下

AspectJAutoProxyRegistrar类registerBeanDefinitions()方法打上断点.

看注册bean的如何处理?

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

注册一个这个组件, 如果有需要的话

点进去看看

想注册一个AnnotationAwareAspectJAutoProxyCreator的组件, 如果registry已经有了的话,就执行以下操作;

但是我们的注册中还没有, 第一次, 所以来创建一个cls, 用registry把bean的定义做好, bean的名叫做internalAutoProxyCreator

其实就是利用@EnableAspectJAutoProxy中的AspectJAutoProxyRegistrar给我们容器中注册一个AnnotationAwareAspectJAutoProxyCreator组件;

翻译过来其实就叫做 ”注解装配模式的ASPECT切面自动代理创建器”组件

判断if(registry.containsBeanDefinition(ATUO_PROXY_CREATOR_BEAN_NAME))

{

    如果容器中bean已经有了 internalAutoProxyCreator, 执行内部内容

}

else

创建AnnotationAwareAspectJAutoProxyCreator信息; 把此bean注册在registry中.

做完后, 相当于

其实就是 ATUO_PROXY_CREATOR_BEAN_NAME值为internalAutoProxyCreator,给容器中注册internalAutoProxyCreator组件, 该组件类型为AnnotationAwareAspectJAutoProxyCreator.class

 

可以打开之前讲过的Cap6Test, 用到了registry...

 

因此我们要重点研究AnnotationAwareAspectJAutoProxyCreator组件(ASPECT自动代理创建器), 研究这个透了, 整个原理也就明白了, 所有的原理就是看容 器注册了什么组件, 这个组件什么时候工作, 及工作时候的功能是什么?  只要把这几个研究清楚了,原理就都清楚了.

 

AnnotationAwareAspectJAutoProxyCreator神奇的组件分析:

类关系图如下,继承关系:

  AnnotationAwareAspectJAutoProxyCreator

 * AnnotationAwareAspectJAutoProxyCreator

 *    ->AspectJAwareAdvisorAutoProxyCreator

 *        ->AbstractAdvisorAutoProxyCreator

 *           ->AbstractAutoProxyCreator

 *             implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

 *                      关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory

 

SmartInstantiationAwareBeanPostProcessor: bean的后置处理器

BeanFactoryAware 能把beanFacotry bean工厂传进来

通过分析以上的bean继承关系我们发现,   具有BeanPostProcessor特点, 也有Aware接口的特点, 实现了BeanFactoryAware 接口

 

那我们来分析做为beanPostProcessor后置处理器做了哪些工作, 做为BeanFactoryAware又做了哪些工作

 

 

, 分析创建和注册AnnotationAwareAspectJAutoProxyCreator的流程:

1)、register()传入配置类,准备创建ioc容器

2)、注册配置类,调用refresh()刷新创建容器;

3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建(主要是分析创建AnnotationAwareAspectJAutoProxyCreator)

    1)、 先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor

    2)、给容器中加别的BeanPostProcessor

    3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;

    4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;

    5)、注册没实现优先级接口的BeanPostProcessor;

    6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;

       创建internalAutoProxyCreator的BeanPostProcessor【其实就是AnnotationAwareAspectJAutoProxyCreator

       1)、创建Bean的实例

       2)、populateBean;给bean的各种属性赋值

       3)、initializeBean:初始化bean;

              1)、invokeAwareMethods():处理Aware接口的方法回调

              2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()

              3)、invokeInitMethods();执行自定义的初始化方法

              4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();

       4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder

    7)、把BeanPostProcessor注册到BeanFactory中;

       beanFactory.addBeanPostProcessor(postProcessor);

 

注意:以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程

 

           AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor

 

, 如何创建增强的Caculator增强bean流程:

 

  1,refresh--->finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;创建剩下的单实例bean

       1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);

              getBean->doGetBean()->getSingleton()->

       2)、创建bean

              【AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()】

              2.1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;

                  只要创建好的Bean都会被缓存起来

              2.2)、createBean();创建bean;

                  AnnotationAwareAspectJAutoProxyCreator 会在任何bean创建之前先尝试返回bean的实例

                  【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】

                  【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的】

                  2.2.1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation,如果能返回代理对象就使用,如果不能就继续,后置处理器先尝试返回对象;

           bean = applyBeanPostProcessorsBeforeInstantiation():

           拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;

           就执行postProcessBeforeInstantiation

           if (bean != null) {

                  bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

           }

 

                  2.2.2)、doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例;和单实例bean创建流程一样;

      

 

                     

  ,AnnotationAwareAspectJAutoProxyCreator】作用:

    InstantiationAwareBeanPostProcessor

 

  1)、每一个bean创建之前,调用postProcessBeforeInstantiation();

       关心MathCalculator和LogAspect的创建

       1)、判断当前bean是否在advisedBeans中(保存了所有需要增强bean)

       2)、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,

           或者是否是切面(@Aspect)

       3)、是否需要跳过

           1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】

              每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;

              判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true

           2)、永远返回false

 

  2)、创建对象

  postProcessAfterInitialization

       return wrapIfNecessary(bean, beanName, cacheKey);//包装如果需要的情况下

       1)、获取当前bean的所有增强器(通知方法)  Object[]  specificInterceptors

           1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)

           2、获取到能在bean使用的增强器。

           3、给增强器排序

       2)、保存当前bean在advisedBeans中;

       3)、如果当前bean需要增强,创建当前bean的代理对象;

           1)、获取所有增强器(通知方法)

           2)、保存到proxyFactory

           3)、创建代理对象:Spring自动决定

              JdkDynamicAopProxy(config);jdk动态代理;

              ObjenesisCglibAopProxy(config);cglib的动态代理;

       4)、给容器中返回当前组件使用cglib增强了的代理对象;

       5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;

 

 

 

 

 

 

 

关于AnnotationAwareAspectJAutoProxyCreatorCaculator动态代理增强实例的创建见第六次笔记,创建完后开始调用目标方法,可以目标方法div处打上断点,再F5跟进;

注意:本次(第七次)视频可反复多看几遍,可理解AOP核心流程。

   

一,目标方法执行caculator.div()方法执行切面拦截

       容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);

       1)、CglibAopProxy.intercept();拦截目标方法的执行

       2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;

           List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

           1)、List<Object> interceptorList保存所有拦截器 5

              一个默认的ExposeInvocationInterceptor 和 4个增强器;

           2)、遍历所有的增强器,将其转为Interceptor;

              registry.getInterceptors(advisor);

           3)、将增强器转为List<MethodInterceptor>;

              如果是MethodInterceptor,直接加入到集合中

              如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;

              转换完成返回MethodInterceptor数组;

 

       3)、如果没有拦截器链,直接执行目标方法;

           拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)

       4)、如果有拦截器链,把需要执行的目标对象,目标方法,

           拦截器链等信息传入创建一个 CglibMethodInvocation 对象,

           并调用 Object retVal =  mi.proceed();

       5)、拦截器链的触发过程;

           1)、如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;

           2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;

              拦截器链的机制,保证通知方法与目标方法的执行顺序;

      

    总结:

       1)、  @EnableAspectJAutoProxy 开启AOP功能

       2)、 @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator

       3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;

       4)、容器的创建流程:

           1)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象

           2)、finishBeanFactoryInitialization()初始化剩下的单实例bean

              1)、创建业务逻辑组件和切面组件

              2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程

              3)、组件创建完之后,判断组件是否需要增强

                  是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);

       5)、执行目标方法:

           1)、代理对象执行目标方法

           2)、CglibAopProxy.intercept();

              1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)

              2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;

              3)、效果:

                  正常执行:前置通知-》目标方法-》后置通知-》返回通知

                  出现异常:前置通知-》目标方法-》后置通知-》异常通知

 

拦截流程图如下:

CAP11 声明式事务

 

  1. 环境搭建:导入数据源、数据库驱动、Spring-jdbc依赖

pom.xml新增c3p0依赖包(c3p0封装了jdbc 对DataSource接口的实现)

 

pom.xml新增数据库驱动依赖包

 

pom.xml新增spring-jdbc依赖包(jdbcTemplate

 

 

  1. 新建Cap10MainConfig,将数据源和操作模板加载到IOC容器中

 

3,新建Order测试表

 

CREATE TABLE `order` (
  `orderid` int(11) DEFAULT NULL,
  `ordertime` datetime DEFAULT NULL,
  `ordermoney` decimal(20,0) DEFAULT NULL,
  `orderstatus` char(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

4,新建OrderDao操作数据库类

 

5,新建 OrderService类,将orderDao注入进来

 

 

 

6,将OrderService和OrderDao扫描进来,加载到容器

 

7,新建测试用例进入测试(测试结果:正常向数据库插入了一条记录

8,对OrderService引入异常,看是否还能插入数据库?

测试结果:报异常, 但数据库正常插入。

 

9,可以给OrderService添加事务,若出现异常,看是否能全部回滚?

测试结果:事务不起作用, 照样可以成功插入

 

  1. 基于上以分析,其实我们之前在xml配置里, 会配置开启基于注解的事务管理功能

    @EnableTransactionalManagement开启基于注解的事务管理功能,和AOP一样Enablexx

 

再测试,测试结果为:出错啦…………IOC容器没有这个事务管理器bean。

 

 

11,将事务管理器的bean加载到容器中,修改配置类,新增以下注册

再测试,测试结果:正常回滚,没有报错

 

 

 

12, @EnableTransactionManagement源码分析(与AOP的创建拦截流程一致)

 1)、@EnableTransactionManagement

                 利用TransactionManagementConfigurationSelector给容器中会导入组件

                 导入两个组件

                 AutoProxyRegistrar

                 ProxyTransactionManagementConfiguration

 2)、AutoProxyRegistrar:

                 给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;基本的动态代理创建器

                 InfrastructureAdvisorAutoProxyCreator:?

                 利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;

 

 3)、ProxyTransactionManagementConfiguration 做了什么?

                 1、给容器中注册事务增强器;

                       1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解

                       2)、事务拦截器:

                            TransactionInterceptor;保存了事务属性信息,事务管理器;

                            他是一个 MethodInterceptor;

                            在目标方法执行的时候;

                                  执行拦截器链;

                                  事务拦截器:

                                       1)、先获取事务相关的属性

                                       2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger

                                             最终会从容器中按照类型获取一个PlatformTransactionManager;

                                       3)、执行目标方法

                                             如果异常,获取到事务管理器,利用事务管理回滚操作;

                                             如果正常,利用事务管理器,提交事务

                

 

 

 

 

 

 

CAP12 BeanFactory的两个重要后置处理器

                

1,扩展原理-BeanFactoryPostProcessor

BeanFactoryPostProcessor:beanFactory的后置处理器;

作用如下:                    

a),在BeanFactory标准初始化之后调用,来定制和修改BeanFactory的内容;

                b),所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建

 

注意:之前也讲过BeanPostProcessor,它是bean后置处理器,bean创建对象初始化前后进行拦截工作的

 

操作步骤:

1〉新建ExtConfig.java配置类

   

新建JamesBeanFactoryPostProcessor.java处理器类(在com.enjoy.cap12.processor目录下)

 

 

BeanFacotry是在bean组件创建之前还是之后生成的呢?写一个测试用例

不难发现,在“Moon constructor”创建之前,当前9个bean已被加载到beanFactory中了。

测试结果结下:

 

 

 

 那么以上BeanFactoryPostProcessor执行原理是怎么样的呢,打断点F5调试一下:

跟踪debug栈,不难发现以下步骤如下:

  1)、ioc容器创建对象

  2)、invokeBeanFactoryPostProcessors(beanFactory);

       如何找到所有的BeanFactoryPostProcessor并执行他们的方法;

           a)、直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法

 *         b)、在初始化创建其他组件前面执行

 

 

然后再点进去,

 

 

 

 

2,扩展原理-BeanDefinitionRegistryPostProcessor

 

postProcessBeanDefinitionRegistry();在所有bean定义信息将要被加载,bean实例还未创建的;

 

操作步骤:

新建JamesBeanDefinitionRegistryPostProcessor

注意:可使用BeanDefinitionBuilder构建器来创建bean定义信息

测试结果如下:

源码分析:从refresh()-->invokeBeanFactoryPostProcessors()-->PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(), 跟进去即发现代码逻辑如下:

 

所以,在任何情况下都会优先执行BeanDefinitionRegistryPostProcessor的处理器,而BeanFactoryPostProcessor的处理器在它后面执行

 

 

 

3IOC容器处理流程(其实就是研究一下refresh()下的这些方法)

Spring容器的refresh()【创建刷新】;

1prepareRefresh()刷新前的预处理;

         1)、initPropertySources()初始化一些属性设置;子类自定义个性化的属性设置方法;

         2)、getEnvironment().validateRequiredProperties();检验属性的合法等

         3)、earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>();保存容器中的一些早期的事件;

2obtainFreshBeanFactory();获取BeanFactory

         1)、refreshBeanFactory();刷新【创建】BeanFactory

                            110行:创建了一个this.beanFactory = new DefaultListableBeanFactory();

                            设置id

         2)、getBeanFactory();返回刚才GenericApplicationContext创建的BeanFactory对象;

         3)、将创建的BeanFactoryDefaultListableBeanFactory】返回;

 

 

 

3prepareBeanFactory(beanFactory);BeanFactory的预准备工作(以上创建了beanFactory,现在对BeanFactory对象进行一些设置属性);

         1)、设置BeanFactory的类加载器、支持表达式解析器...

         2)、添加部分BeanPostProcessorApplicationContextAwareProcessor

         3)、设置忽略的自动装配的接口EnvironmentAwareEmbeddedValueResolverAwarexxx

         4)、注册可以解析的自动装配;我们能直接在任何组件中自动注入:

                            BeanFactoryResourceLoaderApplicationEventPublisherApplicationContext

         5)、添加BeanPostProcessorApplicationListenerDetector

         6)、添加编译时的AspectJ

         7)、给BeanFactory中注册一些能用的组件;

                   environmentConfigurableEnvironment】、

                   systemPropertiesMap<String, Object>】、

                   systemEnvironmentMap<String, Object>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值