spring-aop源码分析
2019独角兽企业重金招聘Python工程师标准>>>
准备示例代码地址
https://github.com/suzhe2018/spring-basic
1、注解@EnableAspectJAutoProxy
@EnableAspectJAutoProxy注解的作用是开启AOP,下面看看该注解做了哪些事情。
通过查看该注解,可以看出它引入了AspectJAutoProxyRegistrar组件。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { //proxyTargetClass属性,默认false,采用JDK动态代理织入增强(实现接口的方式);如果设为true,则采用CGLIB动态代理织入增强boolean proxyTargetClass() default false;//通过aop框架暴露该代理对象,aopContext能够访问boolean exposeProxy() default false; }
AspectJAutoProxyRegistrar组件实现了ImportBeanDefinitionRegistrar的接口。这是往spring容器中注册bean的一种方式,详细可以参考我的这篇博客
Spring-bean组件注册(https://my.oschina.net/suzheworld/blog/3008094)。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {/*** Register, escalate, and configure the AspectJ auto proxy creator based on the value* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing* {@code @Configuration} class.*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);AnnotationAttributes enableAspectJAutoProxy =AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAspectJAutoProxy != null) {if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}}
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 如果有需要的话,注册AspectJAnnotationAutoProxyCreator。
以debug模式进行测试一下。
进入registerAspectJAnnotationAutoProxyCreatorIfNecessary方法
继续跟进,可以看到调用了registerOrEscalateApcAsRequired方法,并把AnnotationAwareAspectJAutoProxyCreator.class作为一个参数传入。
跟进registerOrEscalateApcAsRequired方法
@Nullable private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,@Nullable Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); //如果registry包含AUTO_PROXY_CREATOR_BEAN_NAME【org.springframework.aop.config.internalAutoProxyCreator】 //这个bean组件,执行内部内容if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());}}return null;} //如果没有注册internalAutoProxyCreator,则注册internalAutoProxyCreator,//类型为AnnotationAwareAspectJAutoProxyCreator.classRootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);return beanDefinition; }
可以看到该方法给容器中注册internalAutoProxyCreator组件, 该组件类型为AnnotationAwareAspectJAutoProxyCreator.class
总结:
spring利用@EnableAspectJAutoProxy中的AspectJAutoProxyRegistrar给我们容器中注册一个AnnotationAwareAspectJAutoProxyCreator组件;
翻译过来其实就叫做 ”注解装配模式的ASPECT切面自动代理创建器”组件。
2、AnnotationAwareAspectJAutoProxyCreator
注解@EnableAspectJAutoProxy向容器中注册了AnnotationAwareAspectJAutoProxyCreator组件,剩下的事就交由AnnotationAwareAspectJAutoProxyCreator组件去负责。下面看看AnnotationAwareAspectJAutoProxyCreator类到底有什么特性,可以实现aop的功能。
AnnotationAwareAspectJAutoProxyCreator继承关系图表
从上面的图中,可以看出AnnotationAwareAspectJAutoProxyCreator具备BeanPostProcessor、Aware、Ordered的特性。
下面分析一下,下面这段代码spring做了什么事
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AopConfig.class);
首先我们可以看到new对象时通过构造函数传入了配置类。
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {this(); //根据配置类向spring容器中注册bean定义信息。register(annotatedClasses); //刷新spring容器,完成bean实例的初始化。refresh(); }
下面看看refresh方法
@Override public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) { //prepareRefresh()刷新前的预处理;prepareRefresh();//获取BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// BeanFactory的预准备工作prepareBeanFactory(beanFactory);try {// BeanFactory准备工作完成后进行的后置处理工作postProcessBeanFactory(beanFactory);// BeanFactory的后置处理器,两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory); // 注册BeanPostProcessor(Bean的后置处理器)【 intercept bean creation】registerBeanPostProcessors(beanFactory); // 初始化MessageSource组件(做国际化功能;消息绑定,消息解析)initMessageSource(); // 初始化事件派发器;initApplicationEventMulticaster();// 留给子容器(子类)去实现onRefresh();// 从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;registerListeners();// 初始化所有剩下的非懒加载的单实例bean;finishBeanFactoryInitialization(beanFactory);//完成BeanFactory的初始化创建工作;IOC容器就创建完成;finishRefresh();}......} }
refresh方法里有个registerBeanPostProcessors,该方法会注册所有实现了BeanPostProcessor的bean到spring容器中,AnnotationAwareAspectJAutoProxyCreator就是在该方法里完成bean的创建和初始化。
下面打个断点,跟进该方法,看看里面到底做了哪些事。
一路跟进,直到方法registerBeanPostProcessors
下面分析一下该方法到底做了哪些事?
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessorString[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));// Separate between BeanPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>(); //优先注册实现了PriorityOrdered接口的BeanPostProcessor; for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, register the BeanPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);// 再给容器中注册实现了Ordered接口的BeanPostProcessor;List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();for (String ppName : orderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}sortPostProcessors(orderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, orderedPostProcessors); // 注册没实现优先级接口的BeanPostProcessor;List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String ppName : nonOrderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);// Finally, re-register all internal BeanPostProcessors.sortPostProcessors(internalPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, internalPostProcessors);// Re-register post-processor for detecting inner beans as ApplicationListeners,// moving it to the end of the processor chain (for picking up proxies etc).beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
注册BeanPostProcessor,实际上就是创建BeanPostProcessor实例,保存在容器中;
debug到下面这行代码,可以看到,调用了beanFactory.getBean方法获取bean实例
跟进getBean方法,可以看到调用了doGetBean方法,一般do开头的方法,都是真正做事的方法。
跟进doGetBean方法,这里用lamda表达式调用了createBean方法去创建bean
进入getSingleton方法
点击下一步直到下面这行代码
跟进这个方法,debug就走到下面这行代码
跟进 createBean方法,一直走到下面这行代码
跟进doCreateBean方法,可以看到该方法所在的类为AbstractAutowireCapableBeanFactory
下面分析一下该方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//创建bean实例instanceWrapper = createBeanInstance(beanName, mbd, args);}......// Initialize the bean instance.Object exposedObject = bean;try {//属性赋值populateBean(beanName, mbd, instanceWrapper);//初始化exposedObject = initializeBean(beanName, exposedObject, mbd);}......return exposedObject; }
以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程,其实在spring中每一个bean的实例化,都会经过上面的这个流程
3、业务类加上aop代理
在refresh方法中调用了下面的方法,该方法完成BeanFactory初始化工作;创建剩下的单实例bean
finishBeanFactoryInitialization(beanFactory);
在类AbstractAutoProxyCreator中的postProcessAfterInitialization方法打一个断点。
不断放行,直到类名为BussinessService
向下执行进入wrapIfNecessary方法。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {..... /***获取当前bean的所有增强器(通知方法) Object[] specificInterceptors* 1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)* 2、获取到能在bean使用的增强器。* 3、给增强器排序*/Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {//2.保存当前bean在advisedBeans中;this.advisedBeans.put(cacheKey, Boolean.TRUE); /* * 如果当前bean需要增强,创建当前bean的代理对象;* 1)、获取所有增强器(通知方法)* 2)、保存到proxyFactory* 3)、创建代理对象:Spring自动决定* JdkDynamicAopProxy(config);jdk动态代理;* ObjenesisCglibAopProxy(config);cglib的动态代理; */Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass()); //返回代理对象return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean; }
生成的代理对象如下,因为BussinessService没有接口,所以采用了cglib的方式生成代理对象。
点击下面标红的地方
可以看出在初始化方法里执行了applyBeanPostProcessorsAfterInitialization方法。
进入该方法可以看到,spring容器中所有BeanPostProcessor类型的实例bean都会对新创建的bean加工处理一遍。
加工处理后的bean就会存储到spring容器中。
4、目标方法执行
上面介绍了AnnotationAwareAspectJAutoProxyCreator 对BussinessService进行了包装,生成了代理类。下面看一看目标方法是如何调用的。
断点打到下面这个位置。
debug进入doBussiness方法,可以看到DynamicAdvisedInterceptor.intercept();拦截目标方法的执行。
@Override @Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Object target = null;TargetSource targetSource = this.advised.getTargetSource();try {if (this.advised.exposeProxy) {oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null); //获取将要执行的目标方法拦截器链;List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);//如果没有拦截器链,直接执行目标方法;retVal = methodProxy.invoke(target, argsToUse);}else {//如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象//然后调用proceed()方法retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal = processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}} }
进入 proceed()方法
@Override @Nullable public Object proceed() throws Throwable { // 如不当前拦截器的索引=interceptorsAndDynamicMethodMatchers的长度-1,也即是说如果到了最后一个拦截器,执行目标方法if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}//获取下一个拦截器Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 如果是动态切面,需要进行参数匹配,以确定是否需要执行该动态横切逻辑InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else { // 动态切面匹配失败,执行链上的下一个拦截器return proceed();}}else { //非动态切面直接调用 MethodInterceptor的invoke方法 传入this即ReflectiveMethodInvocation实例 //传入this进入,这样就可以形成一个调用的链条了return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);} }
因为这里的程序创建的不是动态切面,所以他只会执行else里的逻辑
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
可以在这里打个断点
第1次执行ExposeInvocationInterceptor的invoke方法,该方法会调用mi.proceed(),又在一次执行到return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
第2次拦截器为AspectJAfterThrowingAdvice,该方法同样会调用mi.proceed()方法。如果调用mi.proceed()方法发生了异常,则会执行异常通知方法。
第3次执行AfterReturningAdviceInterceptor里的invoke方法,该方法里也会调用mi.proceed()方法,调用成功后,会执行返回通知方法。
第4次执行AspectJAfterAdvice里的方法,值得注意的是这里执行后置通知方法放在了finally里。所以无论是否发生异常,都会执行。
第5次执行AspectJAroundAdvice里的方法,该方法调用到proceedingJoinPoint.proceed(),又会在一次进入ReflectiveMethodInvocation的proceed()方法。然后会调用最后一个拦截器MethodBeforeAdviceInterceptor,执行前置通知方法。
MethodBeforeAdviceInterceptor方法执行后,会再一次调用mi.proceed(); 此时后面没有拦截器了,目标方法会被执行。
这样不断的调用mi.proceed()方法,直到最后一个拦截器的方法调用完,执行目标方法。通过这种递归调用的方式实现aop各个通知方法的执行。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}
转载于:https://my.oschina.net/suzheworld/blog/3009400
spring-aop源码分析相关推荐
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- Spring AOP 源码分析 - 创建代理对象
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
- Spring AOP 源码分析 - 筛选合适的通知器
1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...
- spring AOP源码分析(一)
spring AOP源码分析(一) 对于springAOP的源码分析,我打算分三部分来讲解:1.配置文件的解析,解析为BeanDefination和其他信息然后注册到BeanFactory中:2.为目 ...
- 一步一步手绘Spring AOP运行时序图(Spring AOP 源码分析)
相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...
- 【Spring】Spring AOP源码分析-导读(一)
文章目录 1.简介 2.AOP 原理 3.AOP 术语及相应的实现 3.1 连接点 - Joinpoint 3.2 切点 - Pointcut 3.3 通知 - Advice 3.4 切面 - Asp ...
- Spring AOP源码分析(八)SpringAOP要注意的地方
2019独角兽企业重金招聘Python工程师标准>>> SpringAOP要注意的地方有很多,下面就举一个,之后想到了再列出来: (1)SpringAOP对于最外层的函数只拦截pub ...
- Spring AOP源码分析(七)ProxyFactoryBean介绍
2019独角兽企业重金招聘Python工程师标准>>> 这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspe ...
- Spring AOP源码分析(四)Spring AOP的JDK动态代理
2019独角兽企业重金招聘Python工程师标准>>> 本篇文章将会介绍上一个例子中的源码执行情况,从中熟悉整个SpringAOP的一些概念和接口设计. 首先整个SpringAOP的 ...
- Spring AOP源码分析二
上一篇中,我们已经找到了AOP的源码入口,我们今天继续分析下面的代码,不过在此之前我们需要看下Spring中如何使用切面的,以便于我们理解我们的源码.代码如下: package com.younger ...
最新文章
- 苏炳添招研究生了!上课画面曝光,网友:千万不要逃课……
- Java网络编程之TCP、UDP
- 表单开发(二):获取单选按钮,多行文本框,下拉菜单,捆绑元素数据,用户注册
- 【Lua】LuaForWindows_v5.1.4-46安装失败解决方案
- Linuxday01基础命令
- 龙图 VP 李翀:数据化运营及云计算下的运维
- 教程:用Java创建和验证JWT
- java里面value_「Java基础知识」Java中包含哪些运算符
- 平台系统云服务器配置,01-云平台连接配置
- 前端诸神大战,Vue、React 依旧笑傲江湖
- 解决ajax回调函数无返回值得问题
- Web API-随机性案例步骤
- Redis 介绍2——常见基本类型
- python 腾讯视频签到_腾讯视频自动签到脚本.
- java字节流字符流复制文件大小不一致及乱码
- coupon优惠券 -- CSS样式
- NetCore3.1开发后台管理系统框架思路与实现
- 《修C传》——初始C语言 <凝气篇>
- 《漫画算法》读书笔记
- 题9.5:有10个学生,每个学生的数据包括学号、姓名、3门课程的成绩,从键盘输人10个 学生数据,要求输出3门课程总平均成绩,以及最高分的学生的数据(包括学号、姓 名、3门课程成绩、平均分数)。