* 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)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
关于AnnotationAwareAspectJAutoProxyCreator和Caculator动态代理增强实例的创建见第六次笔记,创建完后开始调用目标方法,可以目标方法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 声明式事务
- 环境搭建:导入数据源、数据库驱动、Spring-jdbc依赖
在pom.xml新增c3p0依赖包(c3p0封装了jdbc 对DataSource接口的实现)
在pom.xml新增数据库驱动依赖包
在pom.xml新增spring-jdbc依赖包(jdbcTemplate)
- 新建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添加事务,若出现异常,看是否能全部回滚?
测试结果:事务不起作用, 照样可以成功插入
- 基于上以分析,其实我们之前在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的处理器在它后面执行
3,IOC容器处理流程(其实就是研究一下refresh()下的这些方法)
Spring容器的refresh()【创建刷新】;
1、prepareRefresh()刷新前的预处理;
1)、initPropertySources()初始化一些属性设置;子类自定义个性化的属性设置方法;
2)、getEnvironment().validateRequiredProperties();检验属性的合法等
3)、earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>();保存容器中的一些早期的事件;
2、obtainFreshBeanFactory();获取BeanFactory;
1)、refreshBeanFactory();刷新【创建】BeanFactory;
110行:创建了一个this.beanFactory = new DefaultListableBeanFactory();
设置id;
2)、getBeanFactory();返回刚才GenericApplicationContext创建的BeanFactory对象;
3)、将创建的BeanFactory【DefaultListableBeanFactory】返回;
3、prepareBeanFactory(beanFactory);BeanFactory的预准备工作(以上创建了beanFactory,现在对BeanFactory对象进行一些设置属性);
1)、设置BeanFactory的类加载器、支持表达式解析器...
2)、添加部分BeanPostProcessor【ApplicationContextAwareProcessor】
3)、设置忽略的自动装配的接口EnvironmentAware、EmbeddedValueResolverAware、xxx;
4)、注册可以解析的自动装配;我们能直接在任何组件中自动注入:
BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
5)、添加BeanPostProcessor【ApplicationListenerDetector】
6)、添加编译时的AspectJ;
7)、给BeanFactory中注册一些能用的组件;
environment【ConfigurableEnvironment】、
systemProperties【Map<String, Object>】、
systemEnvironment【Map<String, Object>】