梳理AOP核心脉络
- 生成代理对象
目标对象实现了接口,则默认采用JDK动态代理
目标对象没有实现接口,则使用Cglib代理
doCreateBean 的初始化 bean 的地方,就是在这个 initializeBean 方法中,生成并返回代理对象的
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd);
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
生成代理对象就是在这个 afterInitialization 中做的,
循环遍历所有 BeanPostProcessor,调用它的 postProcessAfterInitialization
一路点进入AbstractAutoProxyCreator. wrapIfNecessary 发现
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
proxyFactory.getProxy(classLoader);
createAopProxy().getProxy(classLoader);
首先是获取 AopProxy 对象,发现默认使用的是 cglib 代理
接下来就是调用 AopProxy 类的 getProxy 获取代理类
一步步返回,exposedObject 就是代理类
如果有循环依赖,会触发getSingleton,此时在缓存中查询不到,方法结束
回到 doCreateBean,返回exposedObject ,回到那个带回调函数的 getSingleton 方法中会将当前的代理对象放入缓存, 此时单例缓存池中就真正存放的是一个 cglib 代理对象
- 使用代理对象来调用方法
调用目标方法,发现进入的是 cglib 的代理类 ,会先获取拦截器链,就是在 LogAspect 类中前置和后置通知对应的拦截器。
首先进入 advised.getInterceptorsAndDynamicInterceptionAdvice 方法
首先获取 advice 适配器,用来将我们定义的 advice 转换成 intercepter
然后获取所有的通知,就是在 LogAspect 中配置的前置和后置通知
然后遍历上面获取的所有通知, 判断当前调用的方法,是否跟 pointcut 的 execution 表达式匹配
当确定当前调用的方法需要被拦截时,将 advice 转化为 intercepter ,这个 advice 就是 before 和 after 通知
之后将拦截器放入拦截器链。
然后 获取了拦截器链后,就真正开始执行拦截器中的方法,并调用目标方法
首先创建一个 CglibMethodInvocation,然后调用 proceed,实际调用的是它的父类 ReflectiveMethodInvocation 中的 proceed
proceed有个判断:调用的是拦截器,还是目标方法
currentInterceptorIndex(初始为 -1) 是否等于 interceptorsAndDynamicMethodMatchers 的 (size - 1)
循环这个 interceptorsAndDynamicMethodMatchers,一次调用拦截器的 invoke 方法
比如当前是 MethodBeforeAdviceInterceptor, 进入它的 invoke 方法查看。它在调用目标方法之前,首先调用了拦截器中的方法, 具体是在这个 advice.before 方法中调用, 执行完前置通知后,继续调用 proceed 方法,重新进入前面 proceed 方法
然后执行目标方法 , 调用后置方法 invokeAdviceMethod
到这里为止,一个拦截方法的流程就全部走完了