Spring之AOP流程解析(ProxyFactory)

  本节我们从ProxyFactory开始分析。该类有几个比较重要的方法——addAdvice、addAdvisor、getProxy,其中最后一个方法是我们本节的重点。前两个方法都是向ProxyFactory中成员变量advisors中加入成员,以便后面调用方法时实现拦截。

  这里,我们首先来了解前两个方法。在addAdvice中会调用到addAdvisor,而内部封装的advisor实际类型是DefaultPointcutAdvisor。如下图所示,这里将advice封装到DefaultPointcutAdvisor。这里我们默认只传入advice参数,在DefaultPointcutAdvisor中的成员变量pointcut默认为Pointcut.TRUE,也就是TruePointcut.INSTANCE,他比较特殊的是通过方法getClassFilter返回的是ClassFilter.TRUE,也就是TrueClassFilter.INSTANCE,通过方法getMethodMatcher返回的是MethodMatcher.TRUE,也就是TrueMethodMatcher.INSTANCE。通过他们的matches方法返回值都是true。接着,在addAdvisor方法中调用了addAdvisorInternal,该方法将入参advisor加入成员变量advisors中,然后将其中的值转换为数组赋给成员变量advisorArray(该变量用于后来在方法DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice中构建interceptorList列表),然后调用adviceChanged方法将成员变量methodCache中的值清空。

  下面,我们来到本节的重点ProxyFactory.getProxy,该方法并不复杂,只是返回一个代理对象,该代理对象除了实现了ProxyFactory.targetSource.getTargetClass所实现接口,另外实现了SpringProxy、Advised、DecoratingProxy这三个接口。

  在ProxyFactory.getProxy方法中调用了ProxyCreatorSupport.createAopProxy,该方法首先调用了方法activate,然后通过方法getAopProxyFactory获得成员变量aopProxyFactory,该成员变量在通过ProxyFactory调用时是DefaultAopProxyFactory的实例。关于ProxyCreatorSupport的另一个构造方法,入参为aopProxyFactory,调用是在ProxyFactoryBean.newPrototypeInstance中,我将放在以后来讲解。接下来调用了DefaultAopProxyFactory.createAopProxy,这里的入参就是我们的ProxyFactory,这点需要紧记,因为在后来的代理对象调用方法时会用到,这里的入参接着会传入到接下来构建的AopProxy实现类型中。在DefaultAopProxyFactory.createAopProxy方法中根据情况构造了ObjenesisCglibAopProxy或者JdkDynamicAopProxy。其中JdkDynamicAopProxy是AopProxy基于JDK的实现,而ObjenesisCglibAopProxy是基于Cglib的实现,他直接继承自CglibAopProxy。这里我只分析JdkDynamicAopProxy,大家有兴趣可以看一下ObjenesisCglibAopProxy,二者只是实现方式不同,大体流程是一致的。我们这里然后就调用了JdkDynamicAopProxy.getProxy,这里有一个参数是ClassUtils.getDefaultClassLoader(),该方法获取的是当前线程的ClassLoader,也就是默认的AppLauncher。然后通过方法AopProxyUtils.completeProxiedInterfaces填充了SpringProxy、Advised、DecoratingProxy这三个接口。而后通过Proxy.newProxyInstance方法构建了代理对象,注意,这里的最后一个入参就是我们这里的JdkDynamicAopProxy。

  下面,假设我们调用了返回的代理对象的某个方法,也就是说,我们将来到JdkDynamicAopProxy.invoke。不知道大家是否还记得,在JdkDynamicAopProxy.advised就是在DefaultAopProxyFactory.createAopProxy方法中的入参,也就是我们的ProxyFactory。让我们再回到JdkDynamicAopProxy.invoke方法。这里首先获得了advised.targetSource,也就是ProxyFactory.targetSource。这里的targetSource是在ProxyFactory的构造函数中将入参Object封装后的TargetSource,默认实现是SingletonTargetSource。接着调用了targetSource.getTarget,也就是获取到了我们这里的目标对象,也就是构造ProxyFactory时的入参Object。然后,获取到target的实际类型,调用了advised.getInterceptorsAndDynamicInterceptionAdvice,也就是方法AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice。该方法根据之前传入的advisor构建调用链。由于我们之前并没有调用该方法,因此,在AdvisedSupport.methodCache中并没有该方法的缓存值,然后调用了DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice来构造cached并将其将入到成员变量methodCache中。

  接下来,让我们来到DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice,该方法实现了将入参config中的Advisors转换为通过匹配后的MethodInterceptor列表,也就是真实方法调用前的拦截链。如下图所示,这里是getInterceptorsAndDynamicInterceptionAdvice的完整方法。

  1.首先调用GlobalAdvisorAdapterRegistry.getInstance获得DefaultAdvisorAdapterRegistry。这里我们需要注意的是在DefaultAdvisorAdapterRegistry的构造方法中已经调用registerAdvisorAdapter方法为其成员变量adapters加入了MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter这三个AdvisorAdapter。

  2.调用入参config.getAdvisors获取在ProxyFactory中配置的advisors。

  3.遍历ProxyFactory.advisors,一般来说,在ProxyFactory中加入的advisor是DefaultPointcutAdvisor,实现了接口PointcutAdvisor。因此,这里将advisor强转为PointcutAdvisor,获取其pointcut,紧接着调用Pointcut.getClassFilter,并调用ClassFilter.matches,判断目标类型是否与当前pointcut的ClassFilter相匹配,如果返回值为true,则继续调用PointcutAdvisor.getPointcut.getMethodMatcher获得MethodMatcher,接着判断其是否与目标类型的调用方法相匹配。如果当前调用方法确实是拦截点,就会调用DefaultAdvisorAdapterRegistry.getInterceptors将当前advisor转换为MethodInterceptor列表。

  这里我简单说一下PointcutAdvisor与Advisor。PointcutAdvisor实现接口Advisor,并且增加了方法getPointcut,返回的Pointcut就是用来判断当前执行的方法是否与当前PointcutAdvisor相匹配。而advisor的作用就是用来封装advice,其有一个方法是getAdvice。这里的DefaultAdvisorAdapterRegistry.getInterceptors方法我放到后面来讲解。

  4.将返回的MethodInterceptor数组加入到interceptorList中然后返回。

  这里我们首先来到DefaultAdvisorAdapterRegistry.getInterceptors。

  1.如果通过advisor.getAdvice获取的advice实现了接口MethodInterceptor,则直接将其加入到interceptors列表中。

  2.这里的成员变量adapters就是在DefaultAdvisorAdapterRegistry构造时就填充了MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter。接着遍历adapters并将满足条件的advice封装后加入到interceptors列表中。

  这里我们以MethodBeforeAdviceAdapter为例。在MethodBeforeAdviceAdapter.supportsAdvice方法中仅仅是判断入参advice是否实现了MethodBeforeAdvice接口,如果满足条件,则调用MethodBeforeAdviceAdapter.getInterceptor将advice强转为MethodBeforeAdvice并将其封装到MethodBeforeAdviceInterceptor中。

  到此为止,我们就构造好了AdviceChain,接下来,来到本节的最后一个重点——构造ReflectiveMethodInvocation,并调用其proceed方法。在构造ReflectiveMethodInvocation时,其最后一个入参就是我们刚刚构造好的chain。接下来,我们来到ReflectiveMethodInvocation.proceed。这里的链式调用很类似web应用中的过滤器,可能spirng团队也是经常写web架构的。

  1.这里首先判断当前调用是否已经将所有的调用链完成,如果已经完成,则调用invokeJoinpoint,触发真实要执行的方法。大家可能比较疑惑,这里为什么是interceptorsAndDynamicMethodMatchers.size() - 1,因为这里的currentInterceptorIndex是从-1开始的,如果从0开始的话,那么,显然就没有后面的 - 1。

  2.从interceptorsAndDynamicMethodMatchers列表中获取值,然后调用其invoke方法。这里我把MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor都讲解一下。

  如果这里的MethodInterceptor实际类型是MethodInterceptor,那么调用了MethodBeforeAdviceInterceptor.invoke,注意,这里的入参是ReflectiveMethodInvocation,也就是说,这里在调用了advice.before后,接着调用了ReflectiveMethodInvocation.proceed,接着来到ReflectiveMethodInvocation.proceed。

  然后假设这里的MethodInterceptor实际类型是AfterReturningAdviceInterceptor,这里直接就调用了ReflectiveMethodInvocation.proceed,在其调用完成后,调用了advice.afterReturning。

  接着,我们假设这里的MethodInterceptor实际类型是ThrowsAdviceInterceptor,这里直接调用了ReflectiveMethodInvocation.proceed,不过,这里添加了异常捕获如果获取到对应的Method,则通过invokeHandlerMethod调用捕获异常的方法。然后继续将异常抛出。

  可以说,这里很好的使用的递归的思路,实现了拦截器的链式调用。

  到这里,本节的内容就结束了。尽管内容洋洋洒洒,但是当你调试代码的时候,会发现其实并没有多少东西。希望大家在看本文的时候尽量结合源码调试,以加深理解。如果有疑问或有相关问题探讨,欢迎大家留言。

原文地址:https://www.cnblogs.com/letsfly/p/10660488.html

时间: 2024-10-12 16:34:10

Spring之AOP流程解析(ProxyFactory)的相关文章

spring的AOP个人理解和使用

1什么是AOP:AOP是面向切面编程,也就是说面向某个功能模块编程,典型的应用就是Spring的声明式事务, Spring的AOP事务解析: 在以前的事务管理是要融合在逻辑代码中的,在逻辑代码中决定事务是否提交或者回滚,这样很容易造成代码难以维护,代码冗余 但是使用spring的声明式事务后,只需要在数据库处理方法上注解事务,就可以对操作进行管理,事务的设置和逻辑代码分开,容易维护2AOP有什么作用 :面向切面编程,例如某个功能点,我们只需抽取横切关注点,然后让需要处理这些功能点的方法来使用代理

spring加载bean流程解析

本篇博客的目录: 一:spring读取配置或注解的过程 二:spring的bean的生命周期 三:spring的BeanPostProcessor处理器 四:一些关键性的问题 五:测试 六:总结 一:spring读取配置或注解的过程 1:先通过扫描指定包路径下的spring注解,比如@Component.@Service.@Lazy @Sope等spring识别的注解或者是xml配置的属性(通过读取流,解析成Document,Document)然后spring会解析这些属性,将这些属性封装到Be

Spring Boot AOP解析

Spring Boot AOP 面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面. AOP(Aspect Oriented Program) 面向切面编程 在面向切面编程的思想里面,把功能分为核心业务功能和周边功能. 核心业务,比如登陆,增加数据,删除数据都叫核心业务 周边功能,比如性能统计,日志,事务管理等等 周边功能在 Spring Boot 的面向切面编程AOP思想里,即被定义为切面 在面向切

spring boot 源码解析 启动流程

spring boot 源码解析 启动流程 在面试过程中经常被问到过spring boot的启动流程,今天就翻一下源码整体看一下: 首先,新建一个启动类,可以看到是首先调用的SpringApplication的静态方法run @SpringBootApplication public class SourceReadApplillcation { public static void main(String[] args) { SpringApplication.run(SourceReadAp

spring AOP原理解析

一.介绍 spring AOP:切面编程,是对类功能的增强.功能包括统一的权限控制.日志打印.异常处理等统一化处理: 二.实现方式 spring实现AOP的方式有两种,JDKProxy和CGLIB:spring是依照,如果类实现了接口,则选择JDKProxy,如果未实现接口,则选择CGLIB: 1.JDKProxy:适用于接口实现类,通过创建代理类,同样实现目标类的接口,以此来增强目标类的功能. 1)IUserOperation接口 package com.caocao; /** * Creat

Spring之AOP原理_动态代理

面向方面编程(Aspect Oriented Programming,简称AOP)是一种声明式编程(Declarative Programming).声明式编程是和命令式编程(Imperative Programming)相对的概念.我们平时使用的编程语言,比如C++.Java.Ruby.Python等,都属命令式编程.命令式编程的意思是,程序员需要一步步写清楚程序需要如何做什么(How to do What).声明式编程的意思是,程序员不需要一步步告诉程序如何做,只需要告诉程序在哪些地方做什么

Spring?IOC设计原理解析:本文乃学习整理参考而来

Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. IoC容器的初始化 1. XmlBeanFactory(屌丝IOC)的整个流程 2. FileSystemXmlApplicationContext 的IOC容器流程 1.高富帅IOC解剖 2. 设置资源加载器和资源定位 3.AbstractApplicationContext的refresh函数载入

Spring IoC源码解析之getBean

一.实例化所有的非懒加载的单实例Bean 从org.springframework.context.support.AbstractApplicationContext#refresh方法开发,进入到实例化所有的非懒加载的单实例Bean的finishBeanFactoryInitialization(beanFactory)的方法: protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory bea

Spring IOC初始化深度解析

1.前言 本文是基于JAVA配置方法对Spring IOC进行分析,掌握Spring IOC初始化流程对于我们更好的使用Spring.学习Spring还是很有帮助的,本文所使用的的Spring版本为5.2.2,下面进入分析 2.初始化流程概要图 PS:图比较大,可以选择新标签页打开 3.初始化流程详解 3.1核心对象说明 beanDefinitionMap:单例bean缓存池(对于使用FactoryBean创建出来的bean,并未保存在此map中!FactoryBean的情况,这里面存的是bea