Spring Boot中面向切面编程大家应该是经常会用到,但是作为学生,很多人可能都没想过里面的细节,这里我根据自己已学到的知识做一个简单的论述。
在编写项目的过程中,我们主要是@Aspect声明为切面,用@Pointcut通过切入点表达式将函数声明为切入点并与连接点进行绑定,再之后就是各种增强器Advisor以及切入点表达式了,
AOP思考:
研究各种Enable组件:看有没有给容器注册组件,什么时候工作,各组件相应的功能又是什么
一、bean的初始化
浅层次的:(xml配置文件)
1、读取Spring的配置文件(通过SAX解析XML获得beans并开始解析bean)
2、获得xml文件beans>bean>id,class,反射加载类,实例对象加入到IOC容器中
3、通过getBean获取bean对象
一、bean的通知方法的注册:
1)、获取当前bean的所有增强器(通知方法)Object[] specificInterceptors
- 找到候选的所有增强器(找哪些通知方法是需要切入当前bean方法)
- 获取到能在bean使用的增强器
- 给增强器排序
2)、保存当前bean在advisedBean中;
3)、如果当前bean需要增强,创建当前bean的代理对象;
- 获取当前bean的所有增强器(通知方法)
- 保存到proxyFactory
- 创建代理对象(包括两种代理对象),Spring自动决定
JdkDynamicAopProxy(config),实现了接口的使用该动态代理,具体啥接口有待考究,没有则使用CGlib
ObjebesisCglibAopProxy(config),CGlib
4)、给容器返回当前动态代理对象,以后容器中获取到的就是这个代理对象
以上过程是将bean包装成一个代理对象,代理对象里面是包装了各种通知方法以及目标方法以及他的参数,以后使用bean的方法的时候实际上都是使用的是这个代理对象
二、目标方法执行
容器中保存了组件的代理对象(cglib增强后的对象),这个对象保存了详细信息(增强器,目标对象,相关参数等等)。说到通知的执行,这就不得不牵扯到Spring的一个重要机制:拦截器链MethodInterceptor
1)、CglibAopProxy.intercept();拦截目标方法的执行
2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
List chain=this.advised.getInterceptorsAngDynamicInterceptionAdvice(method,targetClass)
-
List interceptorList保存所有拦截器
一个默认的ExposeInvocationInterceptor和四个增强器 -
遍历所有的增强器,将其转化为Interceptor;
registry.getInterceptors(advisor); -
将增强器转化为List
如果是MethodInterceptor,直接加入集合,如果不是,使用AdvisorAdapter将增强器转化为MethodInterceptor;转换完成MethodInterceptor数组
3)、如果没有拦截器链,直接执行目标方法;主要是根据chain的size来确定的
4)、如果又拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation对象,并调用proceed()方法进行执行,关于proceed()方法,里面大概相当于递归吧,层层递进在函数体内调用proceed()
5)、拦截器的触发过程:
- 如果没有执行拦截器执行目标方法,或者拦截器的索引和拦截器数组-1一样(size-1)(指到了最后一个拦截器)执行目标方法;
- 链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
拦截器链的机制,保证通知方法和目标方法的顺序
以下是执行流程图
关于本文的大部分知识均来自以下Spring原理解析视频
http://www.chilangedu.com/sectionq/1661741327/D1673F086C603782
关于动态代理的部分可以参考以下链接
https://www.cnblogs.com/leifei/p/8263448.html