Spring框架之AOP源码彻底解析html
Spring能够说是Java企业开发里最重要的技术。Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Oriented Programming面向切面编程)。IOC技术咱们在上一篇文章“Spring框架之beans源码彻底解析”中进行了分析,本文对Spring框架的AOP源码进行分析。java
AOP面向切面编程是经过预编译方式和运行其动态代理,实如今不修改源代码的状况下给程序动态统一添加功能的一种技术,是OOP面向对象编程的有效补充。利用AOP技术将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,经过对这些行为的分离,能够将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不会影响业务逻辑的代码,实现了解耦,提升了代码的灵活性和可扩展性。web
下面就Spring框架的AOP源码进行解析,主要从如下几个方面进行剖析:一是对Spring的几个关键概念进行阐述;二是对AOP源码文件清单进行梳理,一共9大类,204个java文件。三是Spring主要使用JDK动态代理来实现AOP,对JDK动态代理作了一个简单的介绍。四是结合源码对Spring AOP的实现原理进行了分析。正则表达式
文章目录spring
1、Spring AOP几个关键概念express
一、AOP联盟apache
二、AOP、Spring AOP、AspectJ的区别编程
三、Spring AOP 10个常见概念设计模式
四、Advice(通知/加强)数组
五、Advisor(顾问/加强器)
六、Pointcut(切点)
七、TargetSource(目标对象)
八、Interceptor(拦截器)
2、AOP源码文件清单
一、aopalliance包含的接口和类
二、AOP包含的接口和类
三、AOP/aspectj包含的接口和类
四、AOP/config包含的接口和类
五、AOP/framework包含的接口和类
六、AOP/interceptor包含的接口和类
七、AOP/scope包含的接口和类
八、AOP/support包含的接口和类
九、AOP/target包含的接口和类
3、JDK动态代理
(一)什么是代理
(二)Java的动态代理类
(三)动态代理的步骤
4、Spring AOP的实现原理
(一)标签的解析
(二)获取加强方法或者加强器
(三)根据获取的加强建立代理
(四)织入
1、Spring AOP几个关键概念
1、AOP联盟
AOP联盟规范了一套用于规范AOP实现的底层API,经过这些统一的底层API,可使得各个AOP实现及工具产品之间实现相互移植。这些API主要以标准接口的形式提供,是AOP编程思想所要解决的横切交叉关注点问题各部件的最高抽象。Spring的AOP框架中也直接以这些API为基础构建。下面咱们来看看当前AOP联盟发布的AOP相关的标准接口。
AOP联盟的API主要包括四个部分,第一个是aop包,定义了一个表示通知Advice的标识接口,各类各样的通知都继承或者实现了该接口。aop包中还包括了一个用于描述AOP系统框架错误运行时异常AspectException。
第二个部分是intercept包,也就是拦截器包,这个包中规范了AOP核心概念中的链接点及通知Advice的类型。
第三部分及第四部分是instrument及reflect包。这两个包中的API主要包括AOP框架或者产品为了实现把横切关注点的模块和核心应用模块组合集成,所须要使用的设施、技术及底层实现规范等。
aopalliance1.0.jar类结构以下图所示(未包括第3、四部分):
aopalliance有三个主要的业务实体:Joinpoint 、Advice、Interceptor。这三个接口构成了aopalliance功能结构。
一、Joinpoint:程序在执行过程当中一个运行时Joinpoint,在这些点关联的静态位置一般会安装有一些Interceptor,当程序运行到这个运行时Joinpoint时,AOP框架会拦截运行时Joinpoint的执行,把运行时Joinpoint交给已经安装的Interceptor们进行处理。JoinPoint接口有三个方法:
proceed():该方法用于执行拦截器逻辑;
getThis():返回保持当前链接点的静态部分的对象;
getStaticPart():返回此链接点的静态部分(一般包含构造函数,成员变量,方法等信息)
二、Advice只是起到一个超类标记功能。Advice(通知)定义了AOP框架在某个Joinpoint(链接点)的通用处理逻辑。
三、Interceptor(拦截器)。Interceptor继承了Advice,能够当作是对Advice的特殊功能实现。Interceptor只是Advice处理逻辑中的一种类型或者方式,表示的仅仅是采用拦截处理机制实现了Advice这种功能。
Advice和Interceptor两个接口没有任何操做,都是标记接口。(标识接口就是空方法的接口。与其余接口的区别是:这个接口里面什么方法都没有,只是标记而已。例如serilizeabled就是这样一个接口,他只是告诉jvm,继承于这个接口的CLASS须要序列化处理,咱们不用实现这个接口的方法。)
2、AOP、Spring AOP、AspectJ的区别
(1)AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,经过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。利用AOP能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。
(2)AspectJ:AspectJ来自于 Eclipse 基金会,属于静态植入,它是经过修改代码来实现的,它的植入时机能够是:Compile-time weaving编译期织入;Post-compile weaving编译后织入,也就是已经生成了.class 文件,或已经达成 jar 包了;Load-time weaving指的是在加载类的时候进行织入。AspectJ 能干不少 Spring AOP 干不了的事情,它是 AOP 编程的彻底解决方案。
(3)SpringAOP:它基于动态代理来实现AOP。若是使用接口的,用JDK提供的动态代理实现,若是没有接口,使用 CGLIB 实现。Spring AOP 致力于解决的是企业级开发中最广泛的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 同样的 AOP 编程彻底解决方案。
AOP是一种概念,springAOP、AspectJ都是AOP的实现,Spring AOP有本身的语法,可是语法复杂,因此SpringAOP借助了AspectJ的注解,可是底层实现仍是本身的。
3、Spring AOP 10个常见概念
(1)Joinpoint(链接点)
程序执行的某个特定位置,好比某个方法调用前、调用后,方法抛出异常后,对类成员的访问以及异常处理程序块的执行等。一个类或一段程序代码拥有一些具备边界性质的特定点,这些代码中的特定点就是链接点。它自身还能够嵌套其余的Joinpoint。AOP中的Joinpoint能够有多种类型:构造方法调用,字段的设置和获取,方法的调用,方法的执行,异常的处理执行,类的初始化。Spring仅支持方法执行类型的Joinpoint。
(2)Pointcut(切点)
若是链接点至关于数据中的记录,那么切点至关于查询条件,一个切点能够匹配多个链接点。因此切点表示一组Joinpoint,这些Jointpoint或是经过逻辑关系组合起来,或是经过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
(3)Advice(通知/加强)
通知是织入到目标类链接点上的一段程序代码。Spring提供的通知接口都是带方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice等。咱们经过AOP将横切关注功能加到原有的业务逻辑上,这是对原有业务逻辑的一种加强,能够是前置、后置、返回后、抛出异常时等。其实Advice翻译成“加强”更合理,更能准确表达其本质。既然大部分文献都是称为通知,咱们这里也称为通知。
(4)Introduction(引介)
引介是一种特殊的通知,它为类添加一些属性和方法。这样,即便一个业务类本来没有实现某个接口,经过引介功能,能够动态的为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
(5)Interceptor(拦截器)
在Advice的基础上扩展定义,定义了通知的加强方式,也就是经过对Joinpoint(链接点)的拦截。一个通用的拦截器能够拦截发生在基础程序中的运行时事件。
(6)Aspect(切面)
切面是由Pointcut(切点)和Advice(通知)组成的,它包括了对横切关注功能的定义,也包括了对链接点的定义。
(7)Advisor(顾问/加强器)
Advisor是切面的另外一种实现,绑定通知跟切点。没有指定切点的通知是没有意义的,Advisor能够说就是一个绑定在指定切点上的通知。它可以将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。
(8)TargetSource(目标对象)
包含链接点的对象。也被称做被通知或被代理对象。
(9)Proxy(代理对象)
包含了原始对象的代码(是在合适的位置调用目标对象的方法)和增长后的代码(Advice通知的内容)的那个对象。
(10)Weaving(织入)
织入是将Advice通知添加到目标类具体链接点上的过程,AOP有三种织入方式:①编译期织入:须要特殊的Java编译期(例如AspectJ的ajc);②装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行加强;③运行时织入:在运行时为目标类生成代理实现加强。
AspectJ采用了编译期织入和装载期织入的方式,Spring采用了动态代理的方式实现了运行时织入。
4、Advice(通知/加强)
Advice有如下几种常见的类型:
一、AspectJMethodBeforeAdvice:前置通知。AspectJ中 before 属性对应的通知(@Before标注的方法会被解析成该通知),在切面方法执行以前执行。
二、AspectJAfterReturningAdvice:后置通知。AspectJ中 afterReturning 属性对应的通知(@AfterReturning 标注的方法会被解析成该通知),在切面方法执行以后执行,若是有异常,则不执行。注意:该通知与AspectJMethodBeforeAdvice对应。
三、AspectJAroundAdvice:环绕通知。AspectJ中 around 属性对应的通知(@Around标注的方法会被解析成该通知),在切面方法执行先后执行。
四、AspectJAfterAdvice:返回通知。AspectJ中 after 属性对应的通知(@After 标注的方法会被解析成该通知),不管是否异常都会执行。
五、AspectJAfterThrowingAdvice:异常通知,AspectJ中 after 属性对应的通知(@AfterThrowing标注的方法会被解析成该通知),在链接点抛出异常后执行。
5、Advisor(顾问/加强器)
advisor:顾问(切面的另外一种实现),封装了spring aop中的切点和通知。通知(advice)中包含了加强的横切代码,切点(pointcut)包含了链接点的描述信息。
一、StaticMethodMatcherPointcut:静态方法切面。定义了一个classFilter,经过重写getClassFilter()方法来指定切面规则。另外实现了StaticMethodMatcher接口,经过重写matches来指定方法匹配规则。
二、StaticMethodMatcherPointcutAdvisor:静态方法匹配切面顾问。扩展了切面排序方法。
三、NameMatchMethodPointcut:名称匹配切面。经过指定方法集合变量mappedNames,模糊匹配。
四、NameMatchMethodPointcutAdvisor:方法名称切面顾问。内部封装了NameMatchMethodPointcut,经过设置方法名称模糊匹配规则和通知来实现切面功能。
五、RegexpMethodPointcutAdvisor:正则表达式切面顾问。可设置多个正则表达式规则,经过内部封装的JdkRegexpMethodPointcut解析正则表达式。
六、DefaultPointcutAdvisor:默认切面顾问。比较灵活,可自由组合切面和通知。
七、InstantiationModelAwarePointcutAdvisorImpl:springboot自动装配的顾问类型。是最经常使用的一种顾问实现。在注解实现的切面中,全部@Aspect类,都会被解析成该对象。
advisorCreator:继承 spring ioc的扩展接口 beanPostProcessor,主要用来扫描获取advisor。
一、AbstractAutoProxyCreator:Spring 为Spring AOP 模块暴露的可扩展抽象类,也是 AOP 中最核心的抽象类。
二、BeanNameAutoProxyCreator:根据指定名称建立代理对象。经过设置 advisor,能够对指定的 beanName 进行代理。支持模糊匹配。
三、AbstractAdvisorAutoProxyCreator:功能比较强大,默认扫描全部Advisor的实现类。相对于根据Bean名称匹配,该类更加灵活。动态的匹配每个类,判断是否能够被代理,并寻找合适的加强类,以及生成代理类。
四、DefaultAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreator的默认实现类。能够单独使用,在框架中使用AOP,尽可能不要手动建立此对象。
五、AspectJAwareAdvisorAutoProxyCreator:AspectJ的实现方式,也是Spring Aop中最经常使用的实现方式,若是用注解方式,则用其子类AnnotationAwareAspectJAutoProxyCreator。
六、AbstractAutoProxyCreator:Spring 为Spring AOP 模块暴露的可扩展抽象类,也是 AOP 中最核心的抽象类。
七、AnnotationAwareAspectJAutoProxyCreator:目前最经常使用的AOP使用方式。spring aop 开启注解方式以后,该类会扫描全部@Aspect()注释的类,生成对应的advisor。目前SpringBoot框架中默认支持的方式,自动配置。
6、Pointcut(切点)
一、AnnotationMatchingPointcut:注解匹配切点。根据类上或方法上是否存在指定的注解判断切点的匹配性,若是没有显示指定注解,则匹配全部。
二、DynamicMethodMatcherPointcut:动态方法匹配器切点。它本质上是一个方法匹配器,但同时具备了切点的功能。
三、ComposablePointcut:可组合的切点。这种切点能够与或逻辑,任意组合其余的Pointcut、ClassFilter和MethodMatcher。其本质是经过ClassFilters和MethodMatchers两个工具类进行Pointcut内部组件的组合。
四、JdkRegexpMethodPointcut: JDK正则表达式切点,即便用正则表达式描述方法的拦截规则和排除规则。
五、AspectJExpressionPointcut:AspectJ切点表达式切点。顾名思义,使用AspectJ的切点表达式描述筛选规则。表达式基本语法以下(非完整语法):execution(<方法修饰符>? <方法返回值类型> <包名>.<类名>.<方法名>(<参数类型>) [throws <异常类型>]?)
其中,‘*’表明0个或多个任意字符,包名中的..(两个点)表明当前包及其子包,参数列表中的..表明任意个参数。如:execution(public static * *..*.*(..) throws *),此表达式匹配全部方法。
7、TargetSource(目标对象)
TargetSource被用于获取当前MethodInvocation(方法调用)所须要的target(目标对象),这个target经过反射的方式被调用(如:method.invode(target,args))。换句话说,proxy(代理对象)代理的不是target,而是TargetSource。
为何Spring AOP代理不直接代理target,而须要经过代理TargetSource(target的来源,其内部持有target),间接代理target呢?
一般状况下,一个proxy(代理对象)只能代理一个target,每次方法调用的目标也是惟一固定的target。可是,若是让proxy代理TargetSource,可使得每次方法调用的target实例都不一样(固然也能够相同,这取决于TargetSource实现)。这种机制使得方法调用变得灵活,能够扩展出不少高级功能,如:target pool(目标对象池)、hot swap(运行时目标对象热替换)等等。
TargetSource组件自己与Spring IoC容器无关,target的生命周期不必定是受spring容器管理的,咱们以往的XML中的AOP配置,只是对受容器管理的bean而言的,咱们固然能够手动建立一个target,同时使用Spring的AOP框架(而不使用IoC容器)
TargetSource包含4个简单实现和3大类实现。
4个简单实现包括:
(1)EmptyTargetSource:静态目标源,当不存在target目标对象,或者甚至连targetClass目标类都不存在(或未知)时,使用此类实例。
(2)HotSwappableTargetSource:动态目标源,支持热替换的目标源,支持spring应用运行时替换目标对象。
(3)JndiObjectTargetSource:spring对JNDI管理bean的支持,static属性可配置。
(4)SingletonTargetSource:静态目标源,单例目标源。Spring的AOP框架默认为受IoC容器管理的bean建立此目标源。换句话说,SingletonTargetSource、proxy与目标bean三者的声明周期均相同。若是bean被配置为prototype,则spring会在每次getBean时建立新的SingletonTargetSource实例。
3大类实现包括:
(1)AbstractBeanFactoryBasedTargetSource:此类目标源基于IoC容器实现,也就是说target目标对象能够经过beanName从容器中获取。此类又扩展出:① SimpleBeanTargetSource:简单实现,直接调用getBean从容器获取目标对象;② LazyInitTargetSource:延迟初始化目标源,子类可重写postProcessTargetObject方法后置处理目标对象;③AbstractPrototypeBasedTargetSource:原型bean目标源,此抽象类可确保beanName对应的bean的scope属性为prototype。其子类作了简单原型、池化原型、线程隔离原型这3种实现。
(2)AbstractRefreshableTargetSource:可刷新的目标源。此类实现可根据配置的刷新延迟时间,在每次获取目标对象时自动刷新目标对象。
(3)AbstractLazyCreationTargetSource:此类实如今调用getTarget()获取时才建立目标对象
8、Interceptor(拦截器)
Interceptor(拦截器)定义了通知的加强方式,也就是经过对Joinpoint(链接点)的拦截。一个通用的拦截器能够拦截发生在基础程序中的运行时事件。这些事件被链接点具体化。运行时链接点能够是一次方法调用、字段访问、异常产生等等。Interceptor接口也在强调概念而非功能,也是一个标记接口。 由Interceptor扩展出的ConstructorInterceptor和MethodInterceptor两个子接口,才具体定义了拦截方式。它们一个用于拦截构造方法,一个用于拦截普通方法。 可是,spring框架并无支持AOP联盟对构造方法的拦截,由于spring框架自己,经过BeanPostProcessor的定义,对bean的生命周期扩展已经很充分了。
MethodInterceptor只定义了加强方式,咱们能够经过实现此接口,自定义具体的加强内容。固然,spring框架也提供了3种预约义的加强内容:BeforeAdvice(前置通知)、AfterAdvice(后置通知)和DynamicIntroductionAdvice(动态引介通知)。BeforeAdvice和AfterAdvice更确切地说是定义了加强内容的执行时机(方法调用以前仍是以后);而DynamicIntroductionAdvice比较特殊,它能够编辑目标类要实现的接口列表。最后,spring预约义的通知仍是要经过对应的适配器,适配成MethodInterceptor接口类型的对象(如:MethodBeforeAdviceInterceptor负责适配MethodBeforeAdvice)。
几个经常使用拦截器:
(1)MethodBeforeAdviceInterceptor:MethodBeforeAdvice(前置通知,其父接口是BeforeAdvice)接口的适配器,用于支持spring预约义的前置通知,在目标方法调用前调用MethodBeforeAdvice.before()。
(2)AspectJAfterAdvice :AspectJ框架的后置通知实现,在目标方法执行结束后,return以前,调用配置指定的方法(注意:此方法调用被写在finally块中,不管如何都会获得执行)。
(3)AfterReturningAdviceInterceptor :AfterReturningAdvice接口的适配器,用于支持spring预约义的后置通知,在目标方法执行结束后,return以前,调用AfterReturningAdvice.afterReturning()执行(注意:若是目标方法抛出异常,则不会执行这个方法)。
(4)AspectJAfterThrowingAdvice :AspectJ框架的异常通知,当目标方法执行时产生异常的时候,指定配置指定的方法。
(5)AspectJAroundAdvice :AspectJ框架的环绕通知,直接执行配置指定的方法。
(6)ThrowsAdviceInterceptor :spring框架预约义的异常通知的适配器,此适配器接受任意类型的对象,可是要求对象所在类必须声明public的名称为afterThrowing,且参数个数为1个或4个,且最后一个参数为Throwable类型的方法。该适配器会保存该Throwable对象的实际类型到该方法之间的映射,当目标方法执行产生异常时,根据产生的异常类型找到对应的通知方法进行调用。
(7)DelegatingIntroductionInterceptor:经过构造方法传入指定的引介对象,每当调用的目标方法是引介接口定义的方法时,都会调用该引介对象的对应方法。
(8)DelegatePerTargetObjectIntroductionInterceptor:经过构造函数传入指定的引介接口和接口对应的实现类,该拦截器会为每一个目标对象建立新的引介对象(经过调用实现类的默认无参构造)。当调用的方法是引介接口定义的方法时,则调用该新建的引介对象对应的方法。
2、AOP源码文件清单
本文进行梳理的AOP源码文件清单是基于版本号为5.2.4.BUILD-SNAPSHOT的Spring源码。一共9大类,204个java文件。
1、aopalliance
aopalliance/aop
1.1 Advice:定义了一个表示通知的标识接口,各类各样的通知都继承或实现了该接口。
1.2 AspectException:描述AOP系统框架错误的运行时异常。
aopalliance/intercept
1.3 Joinpoint:链接点。在拦截器中使用,封装了原方法调用的相关信息,如参数、原对象信息,以及直接调用原方法的proceed方法。
1.4 Invocation 运行时的方法调用,继承自joinpoint。
1.5 ConstructorInvocation:Invocation的子类,包含了获取构造器的方法。
1.6 MethodInvocation:Invocation的子类,返回被调用的方法信息。
1.7 Interceptor:拦截器,Advice的子接口,标记拦截器。拦截器是加强器的一种。
1.8 ConstructorInterceptor:构造器拦截器,Interceptor的子接口,拦截构造器并处理。
1.9 MethodInterceptor:方法拦截器,Interceptor的子接口,拦截方法并处理,核心类。
2、AOP
2.1 Pointcut:切点的一个顶层抽象。切点的主要做用是定义通知所要应用到的类跟方法。具体的哪些类、哪些方法由ClassFilter和MethodMatcher匹配,只有知足切入点的条件时才插入advice。
2.2 TruePointcut:Pointcut(切点)接口的一个最简单的实现类,匹配到全部。
2.3 AfterAdvice:不管一个 join point 是正常退出仍是发生了异常, 都会被执行的 advice。
2.4 AfterReturningAdvice:后置通知(After Returning Advice)后置通知相比较于前置通知,主要有如下几点不一样:后置通知能够访问目标方法的返回值,可是不能修改,后置通知是在方法执行完成后执行。
2.5 BeforeAdvice:在 join point 前被执行的 advice。虽然 before advice 是在 join point 前被执行,可是它并不可以阻止 join point 的执行,除非发生了异常(即咱们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)。
2.6 MethodBeforeAdvice:前置通知(Before Advice)跟环绕通知不一样的是,这个接口中定义的方法的返回值是void,因此前置通知是没法修改方法的返回值的。若是在前置通知中发生了异常,那么会直接终止目标方法的执行以及打断整个拦截器链的执行。
2.7 ThrowsAdvice:异常通知(Throws Advice),其中没有定义任何方法,它更像一个标记接口。咱们在定义异常通知时须要实现这个接口,同时方法的签名也有要求:一、方法名称必须是afterThrowing。二、方法的参数个数必须是1个或者4个。
2.8 Advisor:顾问,封装了spring aop中的切点和通知。 就是咱们经常使用的@Aspect 注解标记的类。
2.9 PointcutAdvisor:表明具备切点的切面,它包含Advice和Pointcut两个类,这样就能够经过类、方法名以及方法方位等信息灵活地定义切面的链接点,提供更具适用性的切面。其有6种实现类:
DefaultPointcutAdvisor:最经常使用的切面类型,它能够经过任意Pointcut和Advice定义一个切面,惟一不支持的是引介的切面类型,通常能够经过扩展该类实现自定义的切面;
NameMatchMethodPointcutAdvisor:经过该类能够定义,按方法名定义切点的切面;
RegexpMethodPointcutAdvisor:按正则表达式匹配方法名进行切点定义的切面;
StaticMethodMatcherPointcutAdvisor:静态方法匹配器切点定义的切面;
AspecJExpressionPointcutAdvisor:Aspecj切点表达式定义切点的切面;
AspecJPointcutAdvisor:使用AspecJ语法定义切点的切面。
2.10 MethodMatcher:用来匹配方法。MethodMatcher中一共有三个核心方法:
matches(Method method, @Nullable Class<?> targetClass),这个方法用来判断当前定义的切点跟目标类中的指定方法是否匹配,它能够在建立代理的时候就被调用,从而决定是否须要进行代理,这样就能够避免每次方法执行的时候再去作判断。
isRuntime(),若是这个方法返回true的话,意味着每次执行方法时还须要作一次匹配。
matches(Method method, @Nullable Class<?> targetClass, Object... args),当以前的isRuntime方法返回true时,会调用这个方法再次进行一次判断,返回false的话,意味着不对这个方法应用通知。
接口的实现类有不少,如StaticMethodMatcher(只支持静态匹配,两个参数的matchs)、AspectJExpressionPointcut(AOP重要组件)、TrueMethodMatcher(老是匹配)、AnnotationMethodMatcher(注解匹配)。
2.11 TrueMethodMatcher:MethodMatcher接口的一个最简单的实现类,匹配到全部的方法。
2.12 ClassFilter:主要做用是在类级别上对通知的应用进行一次过滤,若是它的match方法对任意的类都返回true的话,说明在类级别上咱们不须要过滤,这种状况下,通知的应用,就彻底依赖MethodMatcher的匹配结果。ClassFilter有4中简单方式的实现:
(1)TypePatternClassFilter:基于AspectJ的类型匹配实现;
(2)AnnotationClassFilter:经过检查目标类是否存在指定的注解,决定是否匹配;
(3)RootClassFilter:经过判断目标类是不是指定类型(或其子类型),决定是否匹配;
(4)TrueClassFilter:这是最简单实现,matches方法总会返回true。此类设计使用了单例模式,且其对象引用直接被在ClassFilter接口中声明成了常量。
2.13 TrueClassFilter:ClassFilter接口的一个最简单的实现类,匹配到全部的类。
2.14 IntroductionInfo:描述一个引介须要的基本信息。引介(Introduction)是指在不更改源代码的状况,给一个现有类增长属性、方法,以及让现有类实现其它接口或指定其它父类等,从而改变类的静态结构。是另外一种类型的加强,和通知是并列的两种不一样的加强。
2.15 IntroductionAdvisor:advisor顾问,封装了spring aop中的切点和通知。这个接口是用来处理一个或者多个引入的顾问的父接口。
2.16 DynamicIntroductionAdvice:引介通知(Introduction Advice)。
2.17 IntroductionAwareMethodMatcher:继承自MethodMatcher,在进行方法匹配时考虑了引入。
2.18 IntroductionInterceptor:AOP联盟中的MethodInterceptor(方法拦截器,拦截方法并处理)的子接口。
2.19 TargetSource:TargetSource(目标源)是被代理的target(目标对象)实例的来源。
2.20 TargetClassAware:在代理中用来公开目标类的最小接口,主要被代理对象和代理工厂所实现.。全部的Aop代理对象或者代理工厂(proxy factory)都要实现的接口,该接口用于暴露出被代理目标对象类型。
2.21 RawTargetAccess:AOP代理的标记接口,用来返回原始的目标对象。
2.22 SpringProxy:标记接口,Spring使用JDK动态代理或者CGLIB的方式来生成代理对象,其中每一个代理对象都会实现SpringProxy接口。用来断定是不是Spring产生的代理对象。
2.23 ProxyMethodInvocation:MethodInvocation接口的拓展,可以返回一个代理对象,而当前的Method Invocation是经过该代理对象办到的。
2.24 AopInvocationException:由于错误的配置或者始料不及的运行时出现的问题,致使AOP运行时方法调用失败时抛出的异常。
3、AOP/aspectj
3.1 AbstractAspectJAdvice:AOP基类,用来包装AspectJ切面(AspectJ aspect)或AspectJ注解(AspectJ-annotated)的通知方法。
3.2 AspectJAfterAdvice:返回通知,AspectJ中 after 属性对应的通知(@After 标注的方法会被解析成该通知),不管是否异常都会执行。
3.3 AspectJAfterReturningAdvice:后置通知,AspectJ中 afterReturning 属性对应的通知(@AfterReturning 标注的方法会被解析成该通知),在切面方法执行以后执行,若是有异常,则不执行。注意:该通知与AspectJMethodBeforeAdvice对应。
3.4 AspectJMethodBeforeAdvice:前置通知,AspectJ中 before 属性对应的通知(@Before标注的方法会被解析成该通知),在切面方法执行以前执行。
3.5 AspectJAfterThrowingAdvice:异常通知,AspectJ中 after 属性对应的通知(@AfterThrowing标注的方法会被解析成该通知),在链接点抛出异常后执行。
3.6 AspectJAroundAdvice:环绕通知,AspectJ中 around 属性对应的通知(@Around标注的方法会被解析成该通知),在切面方法执行先后执行。
3.7 AspectJPointcutAdvisor:继承自接口PointcutAdvisor,该类用来调整AbstractAspectJAdvice 使其适应PointcutAdvisor接口 。
3.8 AspectJExpressionPointcutAdvisor:用来处理对应 AspectJ 的 advice 和切点的,有advice的设置和获取、切点表达式的一些处理、设置切点的Bean工厂,获取该切点等方法。该类建立了一个 AspectJExpressionPointcut,它们之间的关系是一对一的组合关系。
3.9 DeclareParentsAdvisor:Spring AOP提供的@Before、@After、@AfterReturning、@AfterThrowing、@Around只对类的现有方法进行加强处理。若是须要对现有类增长新的方法,有两种方法可实现:(1)扩展示有类:实现简单,但若是对多个现有类进行扩展时,需增长多个类。(2)使用@DeclareParents注解实现:实现复杂,可以使用通配符匹配。
3.10 InstantiationModelAwarePointcutAdvisor:由spring aop顾问实现的接口,封装了可能具备延迟初始化策略的AspectJ 切面。
3.11 AspectJExpressionPointcut:AspectJ表达式切点(经过解析XML配置文件中的<aop:pointcut>元素生成的就是此类型的bean)。它是一种切点,但与通常的切点不一样,通常的切点须要持有单独的ClassFilter和MethodMatcher。可是AspectJ表达式切点自己就兼具了这两个组件的功能。由于切点表达式,就是用来描述要代理的目标类和目标方法的。
3.12 MethodInvocationProceedingJoinPoint:AspectJ的ProceedingJoinPoint接口的一个实现类,包装了MethodInvocation。Proceedingjoinpoint接口 继承自 JoinPoint,是在JoinPoint的基础上暴露出 proceed 这个方法。环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的,暴露出这个方法,就能支持 aop:around 这种切面。
3.13 AspectInstanceFactory:切面工厂,实现该接口的工厂用来生成AspectJ切面的一个实例。
3.14 SimpleAspectInstanceFactory:该接口主要用于从给定的类(或者 beanName 等)获取一个切面实例,这是AspectInstanceFactory接口的一个实现类。
3.15 SingletonAspectInstanceFactory:AspectInstanceFactory接口的一个实现类,用来支持单例的对象,对于每次调用getAspectInstance(),都返回同一个切面实例。
3.16 AspectJAopUtils:相比于AopUtils,AspectJAopUtils是专门针对于AspectJ advisors的工具类。
3.17 AspectJProxyUtils:它相对于AopProxyUtils,它只是专门处理AspectJ代理对象的工具类。
3.18 AspectJAdviceParameterNameDiscoverer:从切点表达式、返回值、抛出异常来推断一个AspectJ通知方法的参数名,若是不存在一个明确的推断,返回Null。
3.19 AspectJPrecedenceInformation:存储用来给通知、顾问根据AspectJ的排序规则进行排序用的相关信息。
3.20 AspectJWeaverMessageHandler:实现自AspectJ的IMessageHandler接口,与常规Spring消息同样,使用相同的日志系统来对AspectJ编织消息进行路由。
3.21 RuntimeTestWalker:这个类用来封装一些AspectJ内部的结果,在未来解压中再从新推送到AspectJ项目中。
3.22 TypePatternClassFilter:ClassFilter类过滤器。基于AspectJ的类型匹配实现。
AOP/aspectj/annotation
3.23 AspectJAdvisorFactory:该类主要用于对切面的校验,从切面中解析 Advisor, Advice 等。
3.24 AbstractAspectJAdvisorFactory:做为父类完成了 是否切面、切面校验、方法切面注解获取、切面注解封装、切面参数解析等一些列工做,将核心的解析 Advisors Advice 交给了 ReflectiveAspectJAdvisorFactory。
3.25 ReflectiveAspectJAdvisorFactory:获取 Advisors,从 MetadataAwareAspectInstanceFactory (包含有切面的元数据信息)中获取切面元数据信息,将方法切点解析为对应的 AspectJExpressionPointcut(经过切点表达式),而后封装成 InstantiationModelAwarePointcutAdvisorImpl 返回。
3.26 AspectJProxyFactory:建立AspectJ的AOP对象,用于Spring集成AspectJ的做用,此时,就不须要使用AspectJ特定的编译器了。
3.27 MetadataAwareAspectInstanceFactory:AspectInstanceFactory的子接口,返回与AspectJ annotated相关的AspectMetedata。原本AspectInstanceFactory包含该方法是最好的,可是AspectMetedata仅仅使用Java 5,因此咱们须要单独分离出该子接口。
3.28 LazySingletonAspectInstanceFactoryDecorator:简单的装饰,使MetadataAwareAspectInstanceFactory实例化一次。
3.29 SingletonMetadataAwareAspectInstanceFactory:MetadataAwareAspectInstanceFactory的一个实现类,每次调用getAspectInstance()函数时,都会返回同一个实例。
3.30 BeanFactoryAspectInstanceFactory:该类就是AspectInstanceFactory接口的一个实现类,用来生成AspectJ切面的一个实例。须要注意的是若是使用原型模式,实例化屡次,可能返回的不是你想要的。使用LazySingletonAspectInstanceFactoryDecorator包装该类,这样就能够确保每次均可以获得一个新的切面实例。
3.31 PrototypeAspectInstanceFactory:多例专用的工厂。
3.32 SimpleMetadataAwareAspectInstanceFactory:MetadataAwareAspectInstanceFactory的一个实现类,每次调用getAspectInstance()函数时,都会建立指定的切面类的实例。
3.33 AspectMetadata:AspectJ切面类的元数据,每一个切面附加一个额外的Spring AOP切点。该类有属性:aspectName、aspectClass、ajType(transient修饰,表示该属性不须要序列,序列化对象的时候,这个属性就不会被序列化)、perClausePointcut。
3.34 InstantiationModelAwarePointcutAdvisorImpl:AspectJPointcutAdvisor的内部实现,注意对于每个目标方法都会有一个该顾问的实例。
3.35 BeanFactoryAspectJAdvisorsBuilder: Spring AOP内部工具类,用来从bean容器也就是BeanFactory中获取全部使用了@AspectJ注解的bean,最终用于自动代理机制(auto-proxying)。
该工具内部使用了缓存机制,虽然公开的查找方法可能会被调用屡次,但并非每次都会真正查找,而是会利用缓存。最核心的逻辑在其方法buildAspectJAdvisors中,该方法查找容器中全部@AspectJ注解的bean,而后将其中每一个advice方法包装成一个Spring Advisor。最终结果以一个List<Advisor>的形式返回给调用者。
3.36 AnnotationAwareAspectJAutoProxyCreator:目前最经常使用的AOP使用方式。spring aop 开启注解方式以后,该类会扫描全部@Aspect()注释的类,生成对应的advisor。目前SpringBoot框架中默认支持的方式,自动配置。
3.37 NotAnAtAspectException:AopConfigException类的拓展,当试图对一个类生成顾问,可是该类又不是AspectJ 注解类型的切面的时候抛出异常。
AOP/aspectj/autoproxy
3.38 AspectJAwareAdvisorAutoProxyCreator:AspectJ的实现方式,也是Spring Aop中最经常使用的实现方式,若是用注解方式,则用AnnotationAwareAspectJAutoProxyCreator(该类的一个子类)。
3.39 AspectJPrecedenceComparator:排序比较器。它优先比较两个加强器所属的切面大小,若是是同一个切面产生的两个加强器,他们的大小是相同的,则须要拿到它们的声明顺序即InstantiationModelAwarePointcutAdvisorImpl的declarationOrder属性。
4、AOP/config
4.1 PointcutComponentDefinition:建立一个切点的信息。
4.2 AspectComponentDefinition:建立一个切面的信息,包括了嵌套的切点。
4.3 AdvisorComponentDefinition:建立一个顾问的信息,用来弥合经过<aop:advisor>配置的顾问的bean definition和架构中的部件定义。
4.4 AbstractInterceptorDrivenBeanDefinitionDecorator:BeanDefinitionDecorator(接口)装饰相关的自定义属性。该抽象类继承自BeanDefinitionDecorator,用于注册相应的Interceptor bean 定义。
4.5 ScopedProxyBeanDefinitionDecorator:<aop:scoped-proxy>标签是spring<bean>标签的装饰标签,AOP命名空间的三大标签之一,它的做用是对生命周期短的bean提供装饰,使其能被生命周期长的bean正确调用。该类负责对该标签进行解析。
4.6 PointcutEntry:实现了接口ParseState.Entry,表明一个切点的入口。
ParseState(在包org.springframework.beans.factory.parsing中)在解析进程中做为一个简单的基于栈结构的追踪逻辑位置类。该类中有一个内部标记接口Entry,为了进入ParseState,要实现该内部标记接口。
4.7 AdviceEntry:实现了接口ParseState.Entry,表明一个通知的入口。
4.8 AdvisorEntry:实现了接口ParseState.Entry,表明一个顾问的入口。
4.9 AspectEntry:实现了接口ParseState.Entry,表明一个切面的入口。
4.10 SpringConfiguredBeanDefinitionParser:实现了接口BeanDefinitionParser,专门用来解析<aop:spring-configured/>标签。
4.11 AspectJAutoProxyBeanDefinitionParser:是一个实现了BeanDefinitionParser接口的类,专门用于解析切面自动代理的Bean定义的解析工做,重点在其parse方法。
4.12 ConfigBeanDefinitionParser:用来解析<aop:config />标签,并将标签相应的BeanDefinition注册BeanFactory(DefaultListableBeanFactory)。
4.13 AopConfigUtils:这个是关于AOP配置的工具类。由于配置AOP的方式有多种(好比xml、注解等),此工具类就是针对不一样配置,提供不一样的工具方法的。它的好处是无论什么配置,最终走底层逻辑都归一了。
4.14 AopNamespaceHandler:AOP命名空间处理器,Spring为了开放性提供了NamespaceHandler机制,这样咱们就能够根据需求本身来处理咱们设置的标签元素。咱们使用基于xml的spring配置时,可能须要配置如<aop:config />这样的标签,在配置这个标签以前,一般咱们须要引入这个aop所在的命名空间。只有经过配置aop的命名空间才会找到AOP标签的处理器AopNamespaceHandler,在AOP的jar中的spring.handlers配置文件中配置了命名空间和命名空间处理器之间的关系。
4.15 AopNamespaceUtils:处理Spring AOP命名空间的工具类。
4.16 MethodLocatingFactoryBean:实现了FactoryBean接口,经过调用getObject()方法获取MethodLocatingFactory对象。主要做用是经过Bean的名称和方法名定位到这个Method,而后经过反射进行调用。
4.17 SimpleBeanFactoryAwareAspectInstanceFactory:继承自AspectInstanceFactory(切面实例工厂),该类在bean工厂中经过bean的名字能够定位到切面。
5、AOP/framework
5.1 AopProxy:表明一个AopProxy代理对象,能够经过这个对象构造代理对象实例。
5.2 AopProxyUtils:对org.springframework.aop.support.AopUtils的一个补充。其中比较重要的方法: completeProxiedInterfaces(判断一个advised真正须要代理的目标接口列表 )和ultimateTargetClass(获取一个代理对象的最终对象类型)。
5.3 ProxyConfig:AOP配置类,是全部的AOP代理工厂的父类,它包含了建立一个AOP代理所须要的基础的通用的一些配置信息。它有五个属性:
proxyTargetClass 是否直接对目标类进行代理,而不是经过接口产生代理;
optimize 标记是否对代理进行优化;
opaque 标记是否须要阻止经过该配置建立的代理对象转换为Advised类型;
exposeProxy 标记代理对象是否应该被aop框架经过AopContext以ThreadLocal的形式暴露出去;
frozen 标记是否须要冻结代理对象,即在代理对象生成以后,是否容许对其进行修改。
5.4 ProxyProcessorSupport:提供为代理建立器提供了一些公共方法实现。
5.5 ProxyCreatorSupport:这个类的主要做用是为建立一个AOP代理对象提供一些功能支持,经过它的getAopProxyFactory能获取一个建立代理对象的工厂。
5.6 ProxyFactory:ProxyFactory继承自ProxyCreatorSupport,使用它来建立一个代理对象也是要先去设置相关的配置信息,而后再调用建立代理的方法。
5.7 ProxyFactoryBean:ProxyFactoryBean的功能:初始化通知器链,获取单例、原型的Aop代理对象。
5.8 AbstractSingletonProxyFactoryBean:FactoryBean的一个超类,主要用来生成singleton-scoped代理对象。
5.9 AopProxyFactory:AopProxy代理工厂类,用于生成代理对象AopProxy。
5.10 DefaultAopProxyFactory AopProxyFactory:AopProxyFactory默认实现类,核心函数createAopProxy。
5.11 JdkDynamicAopProxy:生成jdk动态代理。能够看到这个类自己就是一个InvocationHandler,这意味着当调用代理对象中的方法时,最终会调用到JdkDynamicAopProxy的invoke方法。
5.12 CglibAopProxy:生成Cglib动态代理。
5.13 ObjenesisCglibAopProxy :该类继承自CglibAopProxy,重写了createProxyClassAndInstance方法。
objenesis是一个小型Java类库用来实例化一个特定class的对象。Java已经支持使用class.newinstance()的类动态实例化,可是必需要有一个合适的构造函数。而不少场景下类不可以用这种方式去实例化,例如:构造函数须要参数(Constructors that require arguments)、有反作用的构造函数(Constructors that have side effects)、会抛出异常的构造函数(Constructors that throw exceptions)。
所以,常见的是在类库中看到类必需要有一个默认的构造函数的限制,Objenesis旨在经过绕过对象实例化的构造函数来克服这些限制。典型用途:(1)序列化,远程调用和持久化-对象须要被实例化并恢复到特定的状态,而不须要调用代码。(2)代理、 AOP 库和 mock 对象-类能够被子类继承而子类不用担忧父类的构造器。(3)容器框架-对象能够以非标准的方式动态地实例化。
5.14 Advised:表明被Advice加强的对象,包括添加advisor的方法、添加advice等的方法。
5.15 AdvisedSupport:ProxyConfig类的子类,封装了AOP中通用的对加强(Advice)和通知器(Advisor)的相关操做,对于全部生成AOP代理对象都通用,而代理对象的生成由子类完成。
5.16 AdvisedSupportListener:监听器,注册在ProxyCreatorSupport对象(用来注册和触发监听器)中,捕获第一个代理建立时和代理建立后通知状态发生改变的事件。
5.17 AopInfrastructureBean:免被AOP代理的标记接口。是一个标记接口。若Bean实现了此接口,代表它是一个Spring AOP的基础类,那么这个类是不会被AOP给代理的,即便它能被切面切进去。
5.18 AbstractAdvisingBeanPostProcessor:继承自BeanPostProcessor,自身内置一个 Advisor,检查当前bean是否符合应用该 Advisor 的条件,符合的话将本身的 Advisor 包裹到当前bean(必要的时候为当前bean建立代理对象以便包裹本身的Advisor)。其中调用了函数AopUtils.canApply(this.advisor, targetClass),用来检查某个 Advisor 是否可应用到某个 bean 上的。
5.19 AopConfigException:AOP配置参数非法时抛出的异常。
5.20 AopContext:表明AOP的上下文。主要是提供咱们访问上下文中当前AOP对象的快速方法。
5.21 AdvisorChainFactory:获取加强器链的工厂接口。提供方法返回全部加强器,以数组返回。
5.22 DefaultAdvisorChainFactory:这个工厂类负责生成拦截器链。借助DefaultAdvisorAdapterRegistry将Advisor集合转换成MethodInterceptor集合。
5.23 InterceptorAndDynamicMethodMatcher:框架的内部类,组合MethodInterceptor实例和MethodMatch做为加强器链中的一个元素。
5.24 ReflectiveMethodInvocation:核心类,激发拦截链工做实现。该类实现了aop联盟的MethodInvocation,间接实现了Invocation和Joinpoint。
AOP/framework/adapter
5.25 AdvisorAdapter:一个适配器接口,它定义了本身支持的Advice类型,而且能把一个Advisor适配成MethodInterceptor。
spring aop框架对BeforeAdvice、AfterAdvice、ThrowsAdvice三种通知类型的支持其实是借助适配器模式来实现的,这样的好处是使得框架容许用户向框架中加入本身想要支持的任何一种通知类型。
5.26 AdvisorAdapterRegistry:顾问适配器注册的接口,这是一个SPI接口,不会被任何Spring用户所实现。java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。
5.27 DefaultAdvisorAdapterRegistry:它用来完成各类通知的适配和注册过程。将Advice包装成Advisor(DefaultPointCutAdvisor),借助AdvisorAdapter,将Advisor包装成MethodInterceptor。
5.28 GlobalAdvisorAdapterRegistry:负责拦截器的适配和注册过程。
5.29 AdvisorAdapterRegistrationManager:继承自BeanPostProcessor后置处理器,利用AdvisorAdapterRegistry在Bean工厂中注册AdvisorAdapter(通知适配器)。
5.30 AfterReturningAdviceAdapter:后置通知适配器。
在 Spring 的 Aop 中,适配器模式应用的很是普遍。Spring 使用 Advice(通知)来加强被代理类的功能,Advice 的类型主要有 BeforeAdvice、AfterReturningAdvice、ThrowsAdvice。每种 Advice 都有对应的拦截器,即 MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。各类不一样类型的 Interceptor,经过适配器统一对外提供接口。最终调用不一样的 advice来实现被代理类的加强。
5.31 AfterReturningAdviceInterceptor:后置通知拦截器。
5.32 MethodBeforeAdviceAdapter:前置通知适配器。
5.33 MethodBeforeAdviceInterceptor:前置通知拦截器。
5.34 ThrowsAdviceAdapter:异常通知适配器。
5.35 ThrowsAdviceInterceptor:异常通知拦截器。
5.36 UnknownAdviceTypeException:当尝试使用一个不支持的顾问或者通知时抛出的异常。
AOP/framework/autoproxy
5.37 AbstractAdvisorAutoProxyCreator:默认扫描全部Advisor的实现类,相对于根据Bean名称匹配,该类更加灵活。动态的匹配每个类,判断是否能够被代理,并寻找合适的加强类,以及生成代理类。
5.38 AbstractAutoProxyCreator:Spring 为Spring AOP 模块暴露的可扩展抽象类,也是 AOP 中最核心的抽象类。自动代理机制的实现其实很简单,就是经过Bean的后置处理器,在建立Bean的最后一步对Bean进行代理,并将代理对象放入到容器中。实现自动代理的核心类就是AbstractAutoProxyCreator。
它的三个具体的实现类来进行分析,分别是BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator、AnnotationAwareAspectJAutoProxyCreator。
5.39 BeanNameAutoProxyCreator:根据指定名称建立代理对象。经过设置 advisor,能够对指定的 beanName 进行代理。支持模糊匹配。
5.40 DefaultAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreator的默认实现类。能够单独使用,在框架中使用AOP,尽可能不要手动建立此对象。
5.41 InfrastructureAdvisorAutoProxyCreator :自动代理建立器,全部的建立器都是AbstractAutoProxyCreator抽象类的子类。该类是Spring给本身内部使用的一个自动代理建立器。它主要是读取Advisor类,并对符合的bean进行二次代理。
5.42 AutoProxyUtils:为自动代理组件准备的工具类。主要用于框架内部使用(AbstractAutoProxyCreator)。
5.43 ProxyCreationContext:当前代理建立的上下文,主要给自动代理建立器使用。好比AbstractAdvisorAutoProxyCreator。
5.44 AbstractBeanFactoryAwareAdvisingPostProcessor:该抽象类定义了这样一类BeanPostProcessor:拥有一个Advisor,对每一个bean进行后置处理,若是该bean符合包裹本身所拥有的Advisor的条件,则将该Advisor包裹该bean。
这里将bean和Advisor包裹该bean的又分两种状况:目标bean是Advised,此时直接使用Advised接口定义的方法添加Advisor到目标bean。目标bean不是Advised,此时为目标对象建立代理对象,并将Advisor添加到目标bean的代理对象上。
以上主要逻辑基本实如今其父类AbstractAdvisingBeanPostProcessor 中,而该类主要是在此基础上实现了BeanFactoryAware接口。并覆盖实现父类的方法prepareProxyFactory,isEligible。
5.45 BeanFactoryAdvisorRetrievalHelper:这个类很重要,是一个Spring AOP内部工具类,用来从bean容器(BeanFactory)中获取全部Spring的Advisor bean(这里的 Spring Advisor bean指的是实现了接口org.springframework.aop.Advisor的bean)。是真正去容器中找出全部的Advisor的类。该工具内部使用了缓存机制,虽然公开的查找方法可能会被调用屡次,但并非每次都会真正查找,而是会利用缓存。
5.46 TargetSourceCreator:建立专用的target source。
AOP/framework/autoproxy/target
5.47 AbstractBeanFactoryBasedTargetSourceCreator:TargetSourceCreator的一个超类,对于一个原型bean须要建立多个实例时使用。使用一个内部的bean工厂去管理这些target实例。
5.48 LazyInitTargetSourceCreator:建立的代理对象并无初始化,直到第一次调用时才进行初始化。
5.49 QuickTargetSourceCreator:根据beanName的不一样前缀建立三种经常使用的TargetSource类型(bean必须为多例)。(1)CommonsPoolTargetSource:池化TargetSource,每次执行方法时从池中取代理对象,执行完方法再返回池中。(2)ThreadLocalTargetSource:线程级的TargetSource。(3)PrototypeTargetSource:多例TargetSource,每次执行方法建立新的代理对象,执行完销毁该对象。
6、AOP/interceptor
6.1 AbstractTraceInterceptor:MethodInterceptor的实现类,主要用于日志记录。默认状况下,写入日志中的消息是记录拦截器类而不是被拦截的类。当把bean属性开关useDynamicLogger设置为true时,拦截器类和被拦截的类日志都会被记录下来。该抽象类的实现子类必须实现方法invokeUnderTrace。
6.2 SimpleTraceInterceptor:继承自AbstractTraceInterceptor, 该拦截器能够引入拦截器链中,用来显示被拦截的方法调用的详细跟踪信息,包括方法进入和退出的信息。 若是想要更高级的需求,能够考虑使用自定义的跟踪拦截器CustomizableTraceInterceptor。
6.3 CustomizableTraceInterceptor:方法级示踪器。 MethodInterceptor的实现类,使用占位符,来进行自定义的方法层级的示踪器。跟踪在方法入口处消息是否写入,在方法退出时判断方法调用是否成功。若是调用出现异常,那么一个异常消息记录下来。这些跟踪消息和占位符是高度定制化的,你能够将一些运行时信息写入日志系统中。
6.4 DebugInterceptor:这个拦截器能够引入链中用来将拦截的调用的一些详细信息显示到日志记录器中。在进行调试时,能够将方法入口和出口处的一些调用细节详细的记录下来,包括调用的参数和调用的次数。
6.5 ExposeInvocationInterceptor:暴露当前MethodInvocation的拦截器。做为线程本地对象, 咱们偶尔须要这样作, 好比切入点时须要知道完整的调用上下文。除非确实有必要,不然不要使用此拦截器。 目标对象应该一般不了解Spring AOP,由于这会产生对Spring API的依赖。目标对象应尽量是普通的POJO。若是要使用这个拦截器,要将这个拦截器放在拦截链中的开头。
6.6 AbstractMonitoringInterceptor:监控拦截器的基类,好比性能监控器。
6.7 PerformanceMonitorInterceptor:性能监控的拦截器,这个拦截器对于被拦截的方法不会有任何附加的做用。其在实际的性能测量时,使用了简洁的耗时统计小工具org.springframework.util.StopWatch。
6.8 JamonPerformanceMonitorInterceptor:性能监控的拦截器,使用了JAMon库对被拦截的方法和输出的状态信息进行性能的监测。另外它也能够对被拦截的方法抛出的异常进行跟踪计数,这些堆栈跟踪足迹能够在JAMopn的web应用中显示出来。
Jamon的全名是:Java Application Monitor。它是一个小巧的,免费的,高性能的,线程安全的性能监测工具。它能够用来测定系统的性能瓶颈,也能够用来监视用户和应用程序之间的交互状况。 Jamon主要是用来检测jee的应用程序。
6.9 ConcurrencyThrottleInterceptor:继承自ConcurrencyThrottleSupport,spring控制并发数的工具类。在ConcurrencyThrottleSupport类中,简单的经过synchronized和wati and notify达到控制线程数量的效果,从而实现限流的策略。
该拦截器中的invoke()方法中,在执行目标方法的先后分别执行beforeAccess()和 afterAccess()方法。在beforeAccess方法中经过内部计数器concurrencyCount来对比设置的阀值concurrencyLimit,若是超过设置值,则阻塞;若没有超过设置值,则concurrencyCount自加。在afterAccess方法中自减concurrencyCount。
6.10 AsyncExecutionAspectSupport:异步任务执行切面的一个基类。核心方法determineAsyncExecutor(),返回一个执行异步任务的线程池AsyncTaskExecutor。
6.11 AsyncExecutionInterceptor:异步任务选择执行器。其核心方法是invoke,主要流程;(1)获取拦截的方法。(2)根据被拦截的方法来选取执行异步任务的执行器。(3)构建任务(添加异常的处理方式)。(4)执行构建的任务并返回任务执行结果。
6.12 AsyncUncaughtExceptionHandler:异步任务执行抛出的异常catch不到时经过此接口进行处理。一个异步任务一般会返回一个java.util.concurrent.Future实例,以访问潜在的异常,当这个异步任务不提供这个返回值时,这个句柄就负责处理此类捕获不到的异常。
6.13 SimpleAsyncUncaughtExceptionHandler:AsyncUncaughtExceptionHandler接口的一个默认实现,用来简单记录这个异常。
6.14 ExposeBeanNameAdvisors:当Spring IOC容器建立自动代理bean时可使用,使得建立顾问更加便捷,将bean name绑定到当前的调用。一般在spring自动代理中使用,在代理建立时,bean的名称就是已知的。
7、AOP/scope
7.1 ScopedObject:用于做用域对象的AOP引介接口。ScopedProxyFactoryBean建立的对象能够转换到这个接口,可以获得原始的目标对象,从它的目标scopt中剥离出该对象。Spring的Bean是有scope属性的,表示bean的生存周期。scope的值有prototype、singleton、session、request。
7.2 DefaultScopedObject:ScopedObject接口的默认实现。
7.3 ScopedProxyFactoryBean:便捷的代理工厂bean,用于做用域对象。被这个工厂bean建立的代理是单例的,线程安全,能够会被注入到共享的对象中。
7.4 ScopedProxyUtils:建立做用域代理的一些功能性类。主要被ScopedProxyBeanDefinitionDecorator 和 ClassPathBeanDefinitionScanner使用。
8、AOP/support
8.1 AbstractExpressionPointcut:表达式切点类型的抽象超类,提供定位和表达式两个属性。
8.2 ExpressionPointcut:表达式切点类型,经过表达式匹配,用于支持AspectJ的表达式。
8.3 NameMatchMethodPointcut:名称匹配切面,经过指定方法集合变量mappedNames,模糊匹配。
8.4 DynamicMethodMatcherPointcut :动态方法匹配器切点。它本质上是一个方法匹配器,但同时具备了切点的功能。
8.5 StaticMethodMatcherPointcut:静态方法切面,抽象类。定义了一个classFilter,经过重写getClassFilter()方法来指定切面规则。另外实现了StaticMethodMatcher接口,经过重写matches来指定方法匹配规则。子类:NameMatchMethodPointcut(简单字符串匹配方法签名)和 AbstractRegexpMethodPointcut(正则表达式匹配方法签名)。
8.6 AbstractRegexpMethodPointcut:正则表达式匹配方法签名。
8.7 JdkRegexpMethodPointcut:JDK正则表达式切点,即便用正则表达式描述方法的拦截规则和排除规则。
8.8 ControlFlowPointcut:流程切点。
8.9 ComposablePointcut:复合切点。这种切点能够与或逻辑,任意组合其余的Pointcut、ClassFilter和MethodMatcher。其本质是经过ClassFilters和MethodMatchers两个工具类进行Pointcut内部组件的组合。
8.10 AbstractPointcutAdvisor:PointcutAdvisor接口的抽象基类,其子类能够返回指定的切点/通知,或者是一个可自由配置的切点/通知。
8.11 AbstractGenericPointcutAdvisor:通常的、通用的PointcutAdvisor。
8.12 DefaultPointcutAdvisor:默认切面顾问,比较灵活。可自由组合切面和通知。
8.13 NameMatchMethodPointcutAdvisor:方法名称切面顾问,内部封装了NameMatchMethodPointcut,经过设置方法名称模糊匹配规则和通知来实现切面功能。
8.14 StaticMethodMatcherPointcutAdvisor:静态方法匹配切面顾问,扩展了切面排序方法。
8.15 RegexpMethodPointcutAdvisor:正则表达式切面顾问,可设置多个正则表达式规则,经过内部封装的JdkRegexpMethodPointcut解析正则表达式。
8.16 DefaultIntroductionAdvisor:默认的引介通知器,它是一种通知器,但同时兼具了类过滤器的功能,且matches总返回true。它的做用是给全部bean追加指定接口。
8.17 AbstractBeanFactoryPointcutAdvisor:基于Bean工厂的切点加强器,容许任何通知配置成指向在bean工厂中的通知bean。经过指定通知bean的名字而不是通知对象自己,在初始化时能够下降耦合度,能够切点真正匹配的时候再去初始化通知对象。
8.18 DefaultBeanFactoryPointcutAdvisor:AbstractBeanFactoryPointcutAdvisor抽象类的实现。基于BeanFactory的PointAdvisor,
8.19 AopUtils:该工具类是Spring很是重要的一个工具类。一个外部工具类,咱们平时若想要对AOP作一些判断、处理,可以使用此工具类。
8.20 Pointcuts:提供了一些静态方法,在操做切点时有用,包括matches、SetterPointcut、GetterPointcut。
8.21 ClassFilters:针对ClassFilter,还有一个工具类——ClassFilters。ClassFilters内部定义了两个私有的静态内部类:IntersectionClassFilter和UnionClassFilter,分别支持以与的逻辑和或的逻辑组合多个ClassFilter。此工具类同时对外提供了组合ClassFilter的API。
8.22 RootClassFilter:经过判断目标类是不是指定类型(或其子类型),决定是否匹配。
8.23 MethodMatchers:同ClassFilters同样,是一个工具类。
8.24 DynamicMethodMatcher:动态方法匹配器的一个抽象超类,主要用于关注运行期间的参数。
8.25 StaticMethodMatcher:静态方法匹配的一个抽象超类,它并不关系运行时期的参数。
8.26 IntroductionInfoSupport:描述一个引介须要的基本信息接口的加强功能,其实现的子类能够方便的从一个指定的对象所实现的全部接口提取出来,将不该该加入的接口排除掉,同时也能够查询全部引入的接口。
8.27 DelegatePerTargetObjectIntroductionInterceptor:引介能够当作一种特殊的Advice,在没有改变原先类的定义的状况下为其增长新的方法。这中通知是spring-aop本身定义的,因此没有相似 @Before 这种配置能够直接注入advice到spring容器中,故此须要本身实现 DynamicIntroductionAdvice 这个接口来进行相应逻辑处理,又因为spring没有对 DynamicIntroductionAdvice 的关于MethodInterceptor的适配器,故此咱们须要实现的实际上是 IntroductionInterceptor 这个接口。DelegatingIntroductionInterceptor 和DelegatePerTargetObjectIntroductionInterceptor 就是接口IntroductionInterceptor的两个实现类。
8.28 DelegatingIntroductionInterceptor:接口IntroductionInterceptor的一个实现类,这个类就是一个委托引入拦截器,具体解释同上。
AOP/support/annotation
8.29 AnnotationClassFilter:经过检查目标类是否存在指定的注解,决定是否匹配
8.30 AnnotationMatchingPointcut:注解匹配切点,JDK5之后,经过注解方式声明切点。根据类上或方法上是否存在指定的注解判断切点的匹配性,若是没有显示指定注解,则匹配全部。
8.31 AnnotationMethodMatcher:注解匹配。寻找指定的Java 5的注解进行简单的方法匹配。
9、AOP/target
9.1 AbstractBeanFactoryBasedTargetSource:此类目标源基于IoC容器实现,也就是说target目标对象能够经过beanName从容器中获取。此类又扩展出:(1)SimpleBeanTargetSource:简单实现,直接调用getBean从容器获取目标对象;(2)LazyInitTargetSource:延迟初始化目标源,子类可重写postProcessTargetObject方法后置处理目标对象;(3)AbstractPrototypeBasedTargetSource:原型bean目标源,此抽象类可确保beanName对应的bean的scope属性为prototype。其子类作了简单原型、池化原型、线程隔离原型这3种实现。
9.2 SimpleBeanTargetSource:AbstractBeanFactoryBasedTargetSource简单实现,直接调用getBean从容器获取目标对象。
9.3 EmptyTargetSource:静态目标源,当不存在target目标对象,或者甚至连targetClass目标类都不存在(或未知)时,使用此类实例。
9.4 HotSwappableTargetSource:动态目标源,支持热替换的目标源,支持spring应用运行时替换目标对象。
9.5 AbstractLazyCreationTargetSource:此类实如今调用getTarget()获取时才建立目标对象。
9.6 LazyInitTargetSource:延迟初始化目标源,子类可重写postProcessTargetObject方法后置处理目标对象。
9.7 SingletonTargetSource:该接口表明一个目标对象,在aop调用目标对象的时候,使用该接口返回真实的对象。Singleton表示每次调用返回同一个实例。
9.8 AbstractPrototypeBasedTargetSource:原型bean目标源,此抽象类可确保beanName对应的bean的scope属性为prototype。其子类作了简单原型、池化原型、线程隔离原型这3种实现。
9.9 PrototypeTargetSource:该接口表明一个目标对象,在aop调用目标对象的时候,使用该接口返回真实的对象。Prototype表示每次调用返回每次调用返回一个新的实例。
9.10 ThreadLocalTargetSource:将获取的bean存储在ThreadLocal ,它在releaseTarget的操做的时候不会从ThreadLocal中释放对应的target。
9.11 ThreadLocalTargetSourceStats:为ThreadLocal目标源作一些统计工做。
9.12 AbstractPoolingTargetSource:这个抽象类实现了PoolConfig,表示是池类的targetSource 。
9.13 PoolingConfig:池类目标对象的配置接口。好比返回池子的最大容量,统计池子中活跃的对象数目,统计池子中空闲的对象数目。
9.14 CommonsPool2TargetSource:利用apache的ObjectPool来存储对应的target对象,它实现了PooledObjectFactory,这个池中的对象仍是从beanFactory中获取。
AOP/target/dynamic
9.15 Refreshable:会被动态目标对象实现的接口,支持经过从新载入,轮询进行刷新。
9.16 AbstractRefreshableTargetSource:可刷新的目标源。此类实现可根据配置的刷新延迟时间,在每次获取目标对象时自动刷新目标对象。
9.17 BeanFactoryRefreshableTargetSource:可刷新的目标源。其target bean是从bean工厂中获取的,每次刷新周期到来时都会自动进行刷新。其子类也能够重写方法requiresRefresh(),把一些没必要要的刷新给取消掉。
3、JDK动态代理
Spring默认采起的动态代理机制实现AOP, 简单来讲就是在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式。动态代理技术包括Java动态代理和CGLIB动态代理,前者基于接口实现,后者基于类实现。Spring默认采起的Java动态代理机制实现AOP。在介绍Spring AOP原理以前先介绍Java动态代理。
(一)什么是代理
编程中有个思想,不要随意的去修改别人已经写好的代码或者方法。可是若是我想在原有实现的基础上增长额外的功能呢,即对目标对象的功能进行拓展。好比在执行某个方法的时候记录下日志,这个时候就可使用代理。
代理是一种常见的设计模式,其目的就是为目标对象提供一个代理对象以控制对目标对象的访问,即经过代理对象访问目标对象。其中代理对象是目标对象的拓展,而且会使用到目标对象。
代理模式又分为静态代理和动态代理。静态代理简单来讲就是代理类和目标类(委托类)实现同一个接口,而后代理类中引入对目标类对象的引用。目的:这样能够实现一些其余功能,可是不会让目标类变得膨胀。缺点:这样必须为目标对象建立一个实现了相同接口的代理对象,而且代理对象中的方法也要和目标对象保持一致。一旦目标对象改动了,代理对象也要变动相应的代码。这样就出现了大量的重复代码,增长了代码的维护复杂度。并且这种方法代理对象只能服务于一种类型的目标对象,若是要服务多个类型的对象,则须要为每一种对象都进行代理。举例:好比我想在调用具体实现类先后打印日志等信息,在不修改已有代码的状况下,咱们只须要增长一个代理类,在代理类中增长打印日志的功能,而后去调用目标类,这样就能够避免修改目标类。在建立代理对象时,经过构造器塞入一个目标对象,而后在代理对象的方法内部调用目标对象同名方法,并在调用先后打印日志。也就是说,代理对象=目标对象+加强代码,有了代理对象以后,就不用原对象了。可是若是想让多个目标类都添加打印日志功能,那么就须要增长多个代理类,代理类中各个方法都要增长打印日志功能,这就不堪负重了。
动态代理:上面咱们知道静态代理每一个代理类只能为一个接口服务,这样程序中就会出现不少代理类,动态代理能够经过一个代理类完成所有的代理功能。这个代理类是在运行时候动态生成的,是经过反射机制动态建立(反射机制是指在运行状态中,对于任意一个类,都能知道这个类的全部属性和方法,对于任意一个对象,都可以调用它的任意属性和方法。)这样不须要为每个接口写一个代理类,避免一个类对应一个代理的问题,大大提升了系统的灵活性,减小重复,下降了代码维护的复杂性和成本。Java动态代理机制以巧妙的方式实践了代理模式的设计理念。
Java动态代理:Java的动态代理是基于接口的,代理类和目标类实现相同的接口,这样他们行为保持了一致性,在访问者看来二者没有丝毫的区别。经过代理类这中间一层,能有效的对委托类的对象的直接访问,能够很好的隐藏和保护委托对象,同时为实施不一样的策略预留空间。
(二)Java的动态代理类
Java动态代理机制中有两个重要的接口和类:接口InvocationHandler()和类Proxy(),位于java.lang.reflect包中,这是实现动态代理的核心。
(1)接口InvocationHandler:动态代理类的调用处理程序
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,该接口中仅定义了一个方法:
public Object invoke(Object proxy, Method method, Object[] args)
其中:第一个参数proxy表示执行这个方法的代理对象,method表示目标对象实际须要执行的方法,args表示目标对象实际要执行的方法所须要的参数。
每个proxy代理实例都要有一个关联的调用处理程序,该调用处理程序都必须实现InvocationHandler接口。因此在实际编程中,须要先定义一个实现了InvocationHandler接口的调用处理器对象,而后将它做为建立代理类实例的参数(见Proxy类的newProxyInstance()方法)。
(2)Proxy:动态代理类
Proxy类就是用来建立一个代理对象的类,最经常使用的方法是static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)。这个方法的做用就是建立一个代理对象,其中三个参数为:
一、ClassLoader loader:指定当前目标对象使用类加载器,对于不一样来源(系统库或网络等)的类须要不一样的类加载器来加载,这是Java安全模型的一部分。
二、Class[] interfaces:一个interface对象数组,目标对象实现的接口的类型。表示咱们要给代理对象提供什么样的接口。若是咱们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就能够调用接口中声明的全部方法。
三、InvocationHandler h:一个InvocationHandler调用处理程序对象,它必须是实现了InvocationHandler接口的对象,做用就是定义代理对象中须要执行的具体操做。当执行目标对象的方法时,会关联到一个InvocationHandler对象上,从而触发调用处理程序的方法,会把当前执行目标对象的方法做为参数传入,并最终调用h中的invoke()方法。
其实动态代理类能够看作是这样一种类:它是在运行时生成的类,在生成它时你必须提供一组接口给它,而后该类就宣称它实现了这些接口。你固然能够把该类的实例当作这里接口中的任何一个来用。固然,这个动态代理类其实就是一个代理,它不会替你作实质性的工做,在生成它的实例时你必须提供一个handler,由它接管实际的工做。在实际使用代理类的时候,咱们必须实现InvocationHandler接口。这样目标对象、须要控制的接口和控制方式均可以动态改变,从而实现灵活的动态代理关系。
(三)动态代理的步骤
一、建立目标类(委托类)的接口
这里定义了两个接口,interface IBusiness1 和interface IBusiness2,各包含一个方法。
interface IBusiness1:
1 package com.dynamicproxy; 2 3 public interface IBusiness1 { 4 public void doSomeThing1() ; 5 }
interface IBusiness2:
1 package com.dynamicproxy; 2 3 public interface IBusiness2 { 4 public void doSomeThing2() ; 5 }
二、建立目标类(委托类)
建立一个目标类Business,实现这两个接口。
1 package com.dynamicproxy; 2 3 public class Business implements IBusiness1, IBusiness2 { 4 @Override 5 public void doSomeThing1() { System.out.println("执行业务逻辑1"); } 6 7 @Override 8 public void doSomeThing2() { 9 System.out.println("执行业务逻辑2"); 10 } 11 }
三、定义一个代理类的调用处理程序。该程序必须实现接口InvocationHandler,且必须实现接口的invoke方法。
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被转发到调用处理程序的invoke方法。
1 package com.dynamicproxy; 2 3 import java.lang.reflect.Method; 4 import java.lang.reflect.InvocationHandler; 5 6 public class LogInvocationHandler implements InvocationHandler{ 7 //目标对象 8 private Object target; 9 10 //构造函数,给目标对象赋值 11 LogInvocationHandler(Object target) { 12 this.target = target; 13 } 14 15 @Override 16 /** 17 * proxy:代理类 18 * method:被代理的方法 19 * args:该方法的参数数组 20 */ 21 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 22 //在真实的对象执行以前添加本身的操做 23 System.out.println("日志: 方法" + method.getName() + "即将执行"); 24 //执行原有逻辑 25 Object rev = method.invoke(target, args); 26 //在真实的对象执行以后添加本身的操做 27 System.out.println("日志: 方法" + method.getName() + "执行完毕"); 28 29 return rev; 30 } 31 }
四、经过Proxy的静态方法newProxyInstance()建立一个代理对象。
Proxy类就是用来建立一个代理对象的类,它提供了不少方法,可是咱们最经常使用的是newProxyInstance方法。这个方法的做用就是建立一个代理类对象。该方法有三个参数,三个参数具体解释见上述。
1 package com.dynamicproxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 public class Test { 7 public static void main(String[] args) { 8 //要代理的目标对象 9 Business myBusiness = new Business(); 10 //代理类要实现的接口列表 11 Class[] proxyInterface = myBusiness.getClass().getInterfaces(); 12 13 //代理对象的调用处理程序。咱们将要代理的目标对象传入代理对象的调用处理的构造函数中,代理对象的调用处理程序最终会调用目标对象的方法 14 LogInvocationHandler handler = new LogInvocationHandler(myBusiness); 15 16 /** 17 * 经过Proxy类的newProxyInstance方法建立代理对象 18 * 第一个参数:handler.getClass().getClassLoader(),使用handler对象的classloader对象来加载咱们的代理对象 19 * 第二个参数:proxyInterface,这里为代理类提供的接口是目标对象实现的接口,这样代理对象就能像目标对象同样调用接口中的全部方法 20 * 第三个参数:handler,咱们将代理对象关联到上面的InvocationHandler对象上 21 */ 22 IBusiness1 proxyBusiness = (IBusiness1) Proxy.newProxyInstance(handler.getClass().getClassLoader(), proxyInterface, handler); 23 24 //使用代理类的实例来调用方法。 25 proxyBusiness.doSomeThing1(); 26 ((IBusiness2) proxyBusiness).doSomeThing2(); 27 } 28 }
五、经过代理对象调用委托类对象的方法。
其实Proxy类只是一个链接桥,把代理(InvocationHandler)与被代理类关联起来,真正处理事情的是InvocaHandler。InvocationHandler接口中的invoke方法在代理类中是动态实现的,当咱们经过动态代理调用一个方法的时候,这个方法的调用会被转发到到调用处理程序的invoke方法中。
1 //使用代理类的实例来调用方法。 2 proxyBusiness.doSomeThing1(); 3 ((IBusiness2) proxyBusiness).doSomeThing2();
运行结果:
动态代理的优点就是能够很方便的对目标类的函数进行统一的处理,而不用修改每一个目标类的方法。全部被代理执行的方法在调用执行的时候,其方法只是做为参数传入InvocationHandler中的invoke方法,实际是在invoke方法中处理的,这样经过在invoke方法中咱们能够对全部被代理的方法进行相同的加强操做。
4、Spring AOP的实现原理
下面Spring AOP实现流程图:
(一)标签的解析
首先咱们来看下AOP经常使用的两种实现方式,一种是采用声明的方式来实现(基于XML),一种是采用注解的方式来实现(基于AspectJ)。下面举例说明:
方式一:xml方式配置
第一步:建立被增强类
1 package cn.ytk.dao; 2 import org.springframework.stereotype.Repository; 3 4 @Repository 5 public class UserDao { 6 public void sys() { 7 System.out.println("userDao....."); 8 } 9 }
第二步:建立加强类
1 package cn.ytk.strong; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 5 public class Project { 6 public void before1() { 7 System.out.println("前置通知。。。。。。。。。"); 8 } 9 //环绕通知 10 public void around(ProceedingJoinPoint point) throws Throwable { 11 System.out.println("环绕通知前。。。。。"); 12 point.proceed(); 13 System.out.println("环绕通知后。。。。。。"); 14 } 15 16 public void after1() { 17 System.out.println("后置通知。。。。。。。。。"); 18 } 19 }
第三步:配置切点和切面
1 <!-- spring bean的配置 --> 2 <bean id="userDao" class="cn.ytk.dao.UserDao"></bean> 3 <bean id="userService" class="cn.ytk.service.UserService"> 4 <property name="userDao" ref="userDao"></property> 5 </bean> 6 <bean id="project" class="cn.ytk.strong.Project"></bean> 7 8 <aop:config> 9 <aop:pointcut expression="execution(* cn.ytk.dao.UserDao.*(..))" id="pointcut1"/> 10 <aop:aspect ref="project"> 11 <aop:before method="before1" pointcut-ref="pointcut1"/> 12 <aop:after-returning method="after1" pointcut-ref="pointcut1"/> 13 <aop:around method="around" pointcut-ref="pointcut1"/> 14 </aop:aspect> 15 </aop:config>
方式二:经过Spring AOP注解实现
第一步:配置spring文件,开启aop注解
1 <!-- 开启aop的注解 --> 2 <aop:aspectj-autoproxy/> 3 <context:component-scan base-package="cn.ytk.*"></context:component-scan>
第二步:编写加强类
1 package cn.ytk.strong; 2 3 import org.aspectj.lang.ProceedingJoinPoint; 4 import org.aspectj.lang.annotation.AfterReturning; 5 import org.aspectj.lang.annotation.Aspect; 6 import org.aspectj.lang.annotation.Before; 7 import org.aspectj.lang.annotation.Pointcut; 8 import org.springframework.stereotype.Component; 9 10 @Component 11 @Aspect 12 public class Project2 { 13 //方式1: 14 @Before(value="execution(* cn.ytk.dao.UserDao.*(..))") 15 public void before() { 16 System.out.println("前置通知。。。。。。"); 17 } 18 19 //方式2:先编写切点在将切点加到增强上。 20 @Pointcut("execution(* cn.ytk.dao.*.*(..))") 21 public void after() {} 22 23 @AfterReturning("after()") 24 public void after1() { 25 System.out.println("....后置通知...."); 26 } 27 }
从示例中看出,XML方式中使用AOP技术的须要作如下几步:
1)开启AOP注解,<aop:aspectj-autoproxy/>
2)定义切面类,使用@Aspect注解
3)在切面类上加设注解@Component
4)在切面类中定义切点方法,使用@PointCut注解
5)在切面类中定义通知方法,使用@Before、@After、@Around等注解
6)在通知方法的注解中使用切点方法
下面结合Spring AOP的源码对AOP的实现原理一步步进行分析:
声明了自定义的注解,必定会在程序的某个地方注册对应的解析器。<aop:aspectj-autoproxy/>注解使用AspectJAutoProxyBeanDefinitionParser解析器进行解析。这个对应关系在AopNamespaceHandler(package org.springframework.aop.config)类中指定。
1 public void init() { 2 // In 2.0 XSD as well as in 2.1 XSD. 3 registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); 4 registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); 5 registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); 6 7 // Only in 2.0 XSD: moved to context namespace as of 2.1 8 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); 9 }
接着来看下AspectJAutoProxyBeanDefinitionParser(package org.springframework.aop.config)解析器的代码。它是一个实现了BeanDefinitionParser接口的类,专门用于解析切面自动代理的Bean定义的解析工做,重点在其parse方法。
1 @Override 2 @Nullable 3 public BeanDefinition parse(Element element, ParserContext parserContext) { 4 //注册AnnotationAwareAspectJAutoProxyCreator 5 AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); 6 //对注解中子类的处理 7 extendBeanDefinition(element, parserContext); 8 return null; 9 }
其中调用了AopNamespaceUtils类(处理Spring AOP命名空间的工具类,package org.springframework.aop.config)的registerAspectJAnnotationAutoProxyCreatorIfNecessary函数。咱们进入此函数看一下代码逻辑:
1 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( 2 ParserContext parserContext, Element sourceElement) { 3 //注册或者升级AutoProxyCreator定义beanName为 4 // org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition 5 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( 6 parserContext.getRegistry(), parserContext.extractSource(sourceElement)); 7 //对于proxy-target-class以及expose-proxy属性的处理 8 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); 9 //注册组件并通知,便于监听器进一步处理,其中BeanDefinition的className 10 // 为AnnotationAwareAspectJAutoProxyCreator 11 registerComponentIfNecessary(beanDefinition, parserContext); 12 }
上述代码一共三行代码,每行代码完成一件事情,都是一个完整的逻辑。
第一行代码:BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement));
注册或者升级AnnotatonAwareAspectJAutoProxyCreator。
咱们进入AopConfigUtils类(package org.springframework.aop.config)的registerAspectJAnnotationAutoProxyCreatorIfNecessary函数看看:
1 @Nullable 2 public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( 3 BeanDefinitionRegistry registry, @Nullable Object source) { 4 5 return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); 6 }
上面这个函数又实际调用了本类中的registerOrEscalateApcAsRequired函数,咱们继续查看该函数的实现逻辑:
1 @Nullable 2 private static BeanDefinition registerOrEscalateApcAsRequired( 3 Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { 4 5 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 6 7 //若是已经存在了自动代理建立器且存在的自动代理建立器与如今的不一致, 8 // 那么须要根据优先级判断到底使用哪一个 9 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { 10 BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); 11 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { 12 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); 13 int requiredPriority = findPriorityForClass(cls); 14 if (currentPriority < requiredPriority) { 15 //改变bean最重要的就是改变bean所对应的className属性 16 apcDefinition.setBeanClassName(cls.getName()); 17 } 18 } 19 //若是已经存在自动代理建立器且与将要建立的一致,那么无需再次建立 20 return null; 21 } 22 23 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); 24 beanDefinition.setSource(source); 25 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); 26 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 27 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); 28 return beanDefinition; 29 }
对于Aop的实现,基本都是靠AnnotatonAwareAspectJAutoProxyCreator去完成的,它能够根据@Point注解定义的切点来自动代理相匹配的bean。可是为了配置简便,Spring使用了自定义的配置帮助咱们自动注册AnnotatonAwareAspectJAutoProxyCreator。其注册过程就是在上述函数中实现的。上述代码实现了自动注册AnnotatonAwareAspectJAutoProxyCreator类的功能,同时存在优先级问题,若是已经存在了自动代理建立器,并且存在的与如今的不一致,那么须要根据优先级判断到底使用哪一个。
第二行代码:useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
处理proxy-target-class和expose-proxy属性,进入该函数:
1 private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) { 2 if (sourceElement != null) { 3 //对应proxy-target-class属性的处理 4 boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE)); 5 if (proxyTargetClass) { 6 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); 7 } 8 //对应expose-proxy属性的处理 9 boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE)); 10 if (exposeProxy) { 11 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); 12 } 13 } 14 }
proxy-target-class和expose-proxy属性解释:
(1)proxy-target-class属性
Spring AOP使用JDK动态代理或者CGLIB来为目标对象建立代理。若是被代理的目标对象至少实现了一个接口,则使用JDK动态代理,全部该目标类型实现的接口都将被代理。若是该目标对象没有实现任何接口,则建立一个CGLIB代理。也能够强制使用CGLIB代理,强制使用CGLIB代理须要将<aop:config>的proxy-target-class属性设置为true:<aop:config proxy-target-class=”true”>…</aop:config>
当须要使用CGLIB代理和@AspectJ自动代理支持,能够按照下面的方式设置<aop:aspectj-autoproxy>的proxy-target-class属性:<aop:aspectj-autoproxy proxy-target-class=”true”>。
(2)expose-proxy属性
Spring AOP没法拦截内部方法调用,好比一个接口里面有两个方法:doSomething1()和doSomething2()。而后在方法1中调用了方法2:this.doSomething2()。此处this指向目标对象,所以调用this.doSomething2()将不会执行doSomething2的加强。(也就是切面只会对doSomething1方法进行加强,可是不会对doSomething2进行加强)。
解决方法:this. doSomething2 ()修改成 ((AService) AopContext.currentProxy()).doSomething2 ()。同时修改Spring AOP的配置:<aop:aspectj-autoproxy expose-proxy="true" />
第三行代码:registerComponentIfNecessary(beanDefinition, parserContext);
注册组件并通知,便于监听器进一步处理。
(二)获取加强方法或者加强器
上面经过自定义配置完成了对AnnotatonAwareAspectJAutoProxyCreator(package org.springframework.aop.aspectj.annotation中)的自动注册。
AnnotatonAwareAspectJAutoProxyCreator类:SpringBoot框架中默认支持的方式。spring aop 开启注解方式以后,该类会扫描全部@Aspect()注释的类,生成对应的advisor。
AnnotationAwareAspectJAutoProxyCreator的继承关系以下:
AnnotationAwareAspectJAutoProxyCreator
--AspectJAwareAdvisorAutoProxyCreator
--AbstractAdvisorAutoProxyCreator
--AbstractAutoProxyCreator
-- ProxyProcessorSupport;
SmartInstantiationAwareBeanPostProcessor;
BeanFactoryAware;
其中
ProxyProcessorSupport
--ProxyConfig;
Ordered;
BeanClassLoaderAware;
AopInfrastructureBean;
SmartInstantiationAwareBeanPostProcessor
--InstantiationAwareBeanPostProcessor
--BeanPostProcessor
BeanFactoryAware
--Aware
AnnotatonAwareAspectJAutoProxyCreator间接实现了BeanPostProcessor接口,因此当Spring加载这个Bean的时候会在实例化以前调用postProcessAfterInitialization这个方法。一直往父类寻找,在其父类AbstractAutoProxyCreator(package org.springframework.aop.framework.autoproxy)实现了该方法。
1 @Override 2 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { 3 if (bean != null) { 4 //根据给定的bean的class和name构建出key,格式:beanClassName_beanName 5 Object cacheKey = getCacheKey(bean.getClass(), beanName); 6 if (this.earlyProxyReferences.remove(cacheKey) != bean) { 7 //一个很是核心的方法:wrapIfNecessary(),若是它适合被代理,则须要封装指定的bean。 8 return wrapIfNecessary(bean, beanName, cacheKey); 9 } 10 } 11 return bean; 12 }
其有一个很是核心的方法:wrapIfNecessary()。继续进入该类中的wrapIfNecessary方法实现逻辑:
1 /** 2 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied. 3 * @param bean the raw bean instance 4 * @param beanName the name of the bean 5 * @param cacheKey the cache key for metadata access 6 * @return a proxy wrapping the bean, or the raw bean instance as-is 7 */ 8 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { 9 //若是已经处理过 10 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { 11 return bean; 12 } 13 //这个bean无需加强 14 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { 15 return bean; 16 } 17 //判断给定的bean是不是一个基础设施类,基础设施类不该代理,或者配置了指定bean不须要代理。 18 //所谓InfrastructureClass就是指Advice/PointCut/Advisor等接口的实现类。 19 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { 20 this.advisedBeans.put(cacheKey, Boolean.FALSE); 21 return bean; 22 } 23 24 // 若是存在加强方法则建立代理 25 //获取这个bean的advice 26 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 27 //若是获取到了加强则须要针对加强建立代理 28 if (specificInterceptors != DO_NOT_PROXY) { 29 this.advisedBeans.put(cacheKey, Boolean.TRUE); 30 //建立代理 31 Object proxy = createProxy( 32 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); 33 this.proxyTypes.put(cacheKey, proxy.getClass()); 34 return proxy; 35 } 36 37 this.advisedBeans.put(cacheKey, Boolean.FALSE); 38 return bean; 39 }
从上述代码中咱们看到了代理建立的雏形。建立代理主要包含了两个步骤:一、获取加强方法或者加强器。二、根据获取的加强进行代理。
下面咱们先来看下获取加强方法或者加强器:
AbstractAutoProxyCreator类的wrapIfNecessary方法中调用了getAdvicesAndAdvisorsForBean,AbstractAutoProxyCreator类只对该方法进行定义,真正实如今其子类AbstractAdvisorAutoProxyCreator(package org.springframework.aop.framework.autoproxy)中实现。
1 protected Object[] getAdvicesAndAdvisorsForBean( 2 Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { 3 4 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); 5 if (advisors.isEmpty()) { 6 return DO_NOT_PROXY; 7 } 8 return advisors.toArray(); 9 }
上面方法实现又调用了该类中的findEligibleAdvisors方法,进入其代码:
1 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { 2 List<Advisor> candidateAdvisors = findCandidateAdvisors(); 3 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); 4 extendAdvisors(eligibleAdvisors); 5 if (!eligibleAdvisors.isEmpty()) { 6 eligibleAdvisors = sortAdvisors(eligibleAdvisors); 7 } 8 return eligibleAdvisors; 9 }
里面有两个函数findCandidateAdvisors和findAdvisorsThatCanApply。这两个方法就是来获取全部的加强以及寻找加强中适用于bean的加强并应用。
(1) findCandidateAdvisors方法(获取全部的加强)
咱们首先进入findCandidateAdvisors看下:
1 protected List<Advisor> findCandidateAdvisors() { 2 Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); 3 return this.advisorRetrievalHelper.findAdvisorBeans(); 4 }
方法中调用了BeanFactoryAdvisorRetrievalHelper类(package org.springframework.aop.framework.autoproxy中)的findAdvisorBeans方法(AbstractAdvisorAutoProxyCreator类中声明了advisorRetrievalHelper是BeanFactoryAdvisorRetrievalHelper类型。private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;)。
BeanFactoryAdvisorRetrievalHelper这个类是一个Spring AOP内部工具类,用来从bean容器中获取全部Spring的Advisor bean(这里的 Spring Advisor bean指的是实现了接口org.springframework.aop.Advisor的bean)。是真正去容器中找出全部的Advisor的类。该工具内部使用了缓存机制,虽然公开的查找方法可能会被调用屡次,但并非每次都会真正查找,而是会利用缓存。
1 public List<Advisor> findAdvisorBeans() { 2 //cachedAdvisorBeanNames是advisor名称的缓存 3 String[] advisorNames = this.cachedAdvisorBeanNames; 4 //若是cachedAdvisorBeanNames为空,则到容器中查找,并设置缓存,后续直接使用缓存便可 5 if (advisorNames == null) { 6 // Do not initialize FactoryBeans here: We need to leave all regular beans 7 // uninitialized to let the auto-proxy creator apply to them! 8 //从容器中查找Advisor类型的bean的名称 9 advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( 10 this.beanFactory, Advisor.class, true, false); 11 this.cachedAdvisorBeanNames = advisorNames; 12 } 13 if (advisorNames.length == 0) { 14 return new ArrayList<>(); 15 } 16 17 List<Advisor> advisors = new ArrayList<>(); 18 //遍历advisorNames 19 for (String name : advisorNames) { 20 if (isEligibleBean(name)) { 21 //忽略郑州建立中的advisor bean 22 if (this.beanFactory.isCurrentlyInCreation(name)) { 23 if (logger.isTraceEnabled()) { 24 logger.trace("Skipping currently created advisor '" + name + "'"); 25 } 26 } 27 else { 28 try { 29 //调用getBean方法从容器中获取名称为name的bean,并将bean添加到advisors中 30 advisors.add(this.beanFactory.getBean(name, Advisor.class)); 31 } 32 catch (BeanCreationException ex) { 33 Throwable rootCause = ex.getMostSpecificCause(); 34 if (rootCause instanceof BeanCurrentlyInCreationException) { 35 BeanCreationException bce = (BeanCreationException) rootCause; 36 String bceBeanName = bce.getBeanName(); 37 if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { 38 if (logger.isTraceEnabled()) { 39 logger.trace("Skipping advisor '" + name + 40 "' with dependency on currently created bean: " + ex.getMessage()); 41 } 42 // Ignore: indicates a reference back to the bean we're trying to advise. 43 // We want to find advisors other than the currently created bean itself. 44 continue; 45 } 46 } 47 throw ex; 48 } 49 } 50 } 51 } 52 return advisors; 53 }
(2)findAdvisorsThatCanApply方法(寻找加强中适用于bean的加强并应用)
咱们首先进入findAdvisorsThatCanApply看下:
1 protected List<Advisor> findAdvisorsThatCanApply( 2 List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { 3 4 ProxyCreationContext.setCurrentProxiedBeanName(beanName); 5 try { 6 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); 7 } 8 finally { 9 ProxyCreationContext.setCurrentProxiedBeanName(null); 10 } 11 }
方法调用了AopUtils类(package org.springframework.aop.support中)的findAdvisorsThatCanApply方法。
1 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { 2 if (candidateAdvisors.isEmpty()) { 3 return candidateAdvisors; 4 } 5 List<Advisor> eligibleAdvisors = new ArrayList<>(); 6 for (Advisor candidate : candidateAdvisors) { 7 //刷选IntroductionAdvisor引介类型的通知器 8 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { 9 eligibleAdvisors.add(candidate); 10 } 11 } 12 boolean hasIntroductions = !eligibleAdvisors.isEmpty(); 13 for (Advisor candidate : candidateAdvisors) { 14 if (candidate instanceof IntroductionAdvisor) { 15 //引介加强已经处理 16 continue; 17 } 18 //刷选普通类型的通知器 19 if (canApply(candidate, clazz, hasIntroductions)) { 20 eligibleAdvisors.add(candidate); 21 } 22 } 23 return eligibleAdvisors; 24 }
该函数调用了该类中的canApply方法,该方法实现了重载,其代码以下:
1 public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { 2 Assert.notNull(pc, "Pointcut must not be null"); 3 //使用 ClassFilter 匹配 class 4 if (!pc.getClassFilter().matches(targetClass)) { 5 return false; 6 } 7 8 MethodMatcher methodMatcher = pc.getMethodMatcher(); 9 if (methodMatcher == MethodMatcher.TRUE) { 10 // No need to iterate the methods if we're matching any method anyway... 11 return true; 12 } 13 14 IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; 15 if (methodMatcher instanceof IntroductionAwareMethodMatcher) { 16 introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; 17 } 18 19 20 /* 21 * 查找当前类及其父类(以及父类的父类等等)所实现的接口,因为接口中的方法是 public, 22 * 因此当前类能够继承其父类,和父类的父类中全部的接口方法 23 */ 24 Set<Class<?>> classes = new LinkedHashSet<>(); 25 if (!Proxy.isProxyClass(targetClass)) { 26 classes.add(ClassUtils.getUserClass(targetClass)); 27 } 28 classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); 29 30 for (Class<?> clazz : classes) { 31 // 获取当前类的方法列表,包括从父类中继承的方法 32 Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); 33 for (Method method : methods) { 34 // 使用 methodMatcher 匹配方法,匹配成功便可当即返回 35 if (introductionAwareMethodMatcher != null ? 36 introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : 37 methodMatcher.matches(method, targetClass)) { 38 return true; 39 } 40 } 41 } 42 43 return false; 44 }
1 public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { 2 if (advisor instanceof IntroductionAdvisor) { 3 /* 4 * 从通知器中获取类型过滤器 ClassFilter,并调用 matchers 方法进行匹配。 5 * ClassFilter 接口的实现类 AspectJExpressionPointcut 为例,该类的 6 * 匹配工做由 AspectJ 表达式解析器负责,具体匹配细节这个就无法分析了,我 7 * AspectJ 表达式的工做流程不是很熟 8 */ 9 return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); 10 } 11 else if (advisor instanceof PointcutAdvisor) { 12 PointcutAdvisor pca = (PointcutAdvisor) advisor; 13 // 对于普通类型的通知器,这里继续调用重载方法进行筛选 14 return canApply(pca.getPointcut(), targetClass, hasIntroductions); 15 } 16 else { 17 // It doesn't have a pointcut so we assume it applies. 18 return true; 19 } 20 }
以上是通知器筛选的过程,筛选的工做主要由 ClassFilter 和 MethodMatcher 完成。
因此获取加强器的主要流程:(1)获取全部bean名称;(2)遍历全部bean名称找出其中标记Aspect的bean;(3)解析并构造获取bean的全部加强器;(4)将解析到的加强器添加到缓存中;(5)过滤匹配出当前bean的加强器。
(三)根据获取的加强建立代理
咱们再回到AbstractAutoProxyCreator类的wrapIfNecessary方法。从这个方法代码中咱们看到了代理建立的雏形。建立代理主要包含了两个步骤:一、获取加强方法或者加强器。二、根据获取的加强进行代理。上面咱们介绍了获取加强方法或者加强器,下面咱们看下根据获取的加强进行代理。
wrapIfNecessary函数中建立代理用了调用了Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
咱们进入AbstractAutoProxyCreator类中的createProxy函数:
1 protected Object createProxy(Class<?> beanClass, @Nullable String beanName, 2 @Nullable Object[] specificInterceptors, TargetSource targetSource) { 3 4 if (this.beanFactory instanceof ConfigurableListableBeanFactory) { 5 AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); 6 } 7 8 ProxyFactory proxyFactory = new ProxyFactory(); 9 //步骤1:获取当前类的属性。 10 proxyFactory.copyFrom(this); 11 12 //步骤2:添加代理接口。 13 if (!proxyFactory.isProxyTargetClass()) { 14 if (shouldProxyTargetClass(beanClass, beanName)) { 15 proxyFactory.setProxyTargetClass(true); 16 } 17 else { 18 evaluateProxyInterfaces(beanClass, proxyFactory); 19 } 20 } 21 22 //步骤3:拦截器封装转化为加强器 23 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); 24 //步骤4:将Advisor加入到ProxyFactory中。 25 proxyFactory.addAdvisors(advisors); 26 //步骤5:设置要代理的类。 27 proxyFactory.setTargetSource(targetSource); 28 //步骤6:为子类提供了定制函数customizeProxyFactory 29 customizeProxyFactory(proxyFactory); 30 31 //步骤7:设置是否须要冻结代理对象。用来控制代理工厂被配置后,是否还容许修改通知。缺省值为false 32 proxyFactory.setFrozen(this.freezeProxy); 33 if (advisorsPreFiltered()) { 34 proxyFactory.setPreFiltered(true); 35 } 36 37 //步骤8:进行代理操做。 38 return proxyFactory.getProxy(getProxyClassLoader()); 39 }
此函数主要是对ProxyFactory的初始化操做,进而对真正的代理建立作准备。这些初始化操做包括:
步骤1:获取当前类的属性。
步骤2:添加代理接口。
步骤3:拦截器封装转化为加强器
步骤4:将Advisor加入到ProxyFactory中。
步骤5:设置要代理的类。
步骤6:在Spring中还为子类提供了定制函数customizeProxyFactory,子类能够在此函数中对ProxyFactory进一步封装。
步骤7:设置是否须要冻结代理对象
步骤8:进行代理操做。
下面咱们重点先来看下步骤三、四、8.
步骤3 :Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
步骤4:proxyFactory.addAdvisors(advisors);
步骤8: return proxyFactory.getProxy(getProxyClassLoader())
(1)步骤3:将拦截器封装转化为加强器。
首先要将拦截器封装转化为加强器,实现函数为buildAdvisors方法,在该类AbstractAutoProxyCreator中,代码以下:
1 protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) { 2 // 解析注册全部的InterceptorNames 3 Advisor[] commonInterceptors = resolveInterceptorNames(); 4 5 List<Object> allInterceptors = new ArrayList<>(); 6 if (specificInterceptors != null) { 7 //加入拦截器 8 allInterceptors.addAll(Arrays.asList(specificInterceptors)); 9 if (commonInterceptors.length > 0) { 10 if (this.applyCommonInterceptorsFirst) { 11 allInterceptors.addAll(0, Arrays.asList(commonInterceptors)); 12 } 13 else { 14 allInterceptors.addAll(Arrays.asList(commonInterceptors)); 15 } 16 } 17 } 18 if (logger.isTraceEnabled()) { 19 int nrOfCommonInterceptors = commonInterceptors.length; 20 int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0); 21 logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors + 22 " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors"); 23 } 24 25 Advisor[] advisors = new Advisor[allInterceptors.size()]; 26 for (int i = 0; i < allInterceptors.size(); i++) { 27 //将拦截器进行封装转化成Advisor 28 advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i)); 29 } 30 return advisors; 31 }
上述方法调用了接口advisorAdapterRegistry的wrap方法,DefaultAdvisorAdapterRegistry类(package org.springframework.aop.framework.adapter)是接口advisorAdapterRegistry的默认实现,用来完成各类通知的适配和注册过程。将Advice包装成Advisor(DefaultPointCutAdvisor),借助AdvisorAdapter,将Advisor包装成MethodInterceptor。咱们进入此类中的wrap方法:
1 @Override 2 public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { 3 //若是要封装的对象自己就是Advisor类型的,那么无需再作过多的处理 4 if (adviceObject instanceof Advisor) { 5 return (Advisor) adviceObject; 6 } 7 //由于此封装方法只对Advisor与Advice两种类型的数据有效,若是不是将不能封装 8 if (!(adviceObject instanceof Advice)) { 9 throw new UnknownAdviceTypeException(adviceObject); 10 } 11 Advice advice = (Advice) adviceObject; 12 if (advice instanceof MethodInterceptor) { 13 //若是是MethodInterceptor类型,则使用DefaultPointcutAdvisor封装 14 return new DefaultPointcutAdvisor(advice); 15 } 16 //若是存在Advisor的适配器,那么也一样须要进行封装 17 for (AdvisorAdapter adapter : this.adapters) { 18 // Check that it is supported. 19 if (adapter.supportsAdvice(advice)) { 20 return new DefaultPointcutAdvisor(advice); 21 } 22 } 23 throw new UnknownAdviceTypeException(advice); 24 }
(2)步骤4:将Advisor加入到ProxyFactory中。
将拦截器封装转化为加强器后,再经过ProxyFactory提供的addAdvisor方法将加强器置入建立工厂中。AbstractAutoProxyCreator.createProxy函数中直接调用了proxyFactory.addAdvisor (advisors)。proxyFactory继承自ProxyCreatorSupport,ProxyCreatorSupport继承自AdvisedSupport。addAdvisor这个方法实际在AdvisedSupport类(package org.springframework.aop.framework)中给出。
1 public void addAdvisor(int pos, Advisor advisor) throws AopConfigException { 2 if (advisor instanceof IntroductionAdvisor) { 3 validateIntroductionAdvisor((IntroductionAdvisor) advisor); 4 } 5 addAdvisorInternal(pos, advisor); 6 }
(3)步骤8:进行获取代理操做。
咱们再回到AbstractAutoProxyCreator.createProxy方法。最后一句代码:return proxyFactory.getProxy(getProxyClassLoader());进行解析最重要的一步就是代理类的建立和处理,Spring委托给了ProxyFactory去处理。咱们进入ProxyFactory类(package org.springframework.aop.framework)中的getProxy函数。
1 public Object getProxy() { 2 // 调用了ProxyCreatorSupport的createAopProxy()方法建立一个AopProxy对象 3 // 而后调用AopProxy对象的getProxy方法 4 return createAopProxy().getProxy(); 5 }
其中就一句话return createAopProxy().getProxy();。createAopProxy 方法没有在ProxyFactory类中定义,createAopProxy方法在其父类ProxyCreatorSupport(package org.springframework.aop.framework)中定义了,进入其代码:
1 protected final synchronized AopProxy createAopProxy() { 2 if (!this.active) { 3 activate(); 4 } 5 // 实际就是使用DefaultAopProxyFactory来建立一个代理对象 6 // 能够看到在调用createAopProxy方法时,传入的参数是this 7 // 这是由于ProxyCreatorSupport自己就保存了建立整个代理对象所须要的配置信息 8 return getAopProxyFactory().createAopProxy(this); 9 }
核心就一句代码return getAopProxyFactory().createAopProxy(this)。实际用的是AopProxyFactory类的createAopProxy方法。AopProxyFactory只是一个接口,DefaultAopProxyFactory(package org.springframework.aop.framework)是AopProxyFactory默认实现类,核心函数createAopProxy。因此实际上是调用了DefaultAopProxyFactory类的createAopProxy方法。
1 @Override 2 // 就是经过AOP相关的配置信息来决定究竟是使用cglib代理仍是jdk代理 3 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 4 // 若是开启了优化,或者ProxyTargetClass设置为true 5 // 或者没有提供代理类须要实现的接口,那么使用cglib代理 6 // 在前面分析参数的时候已经说过了 7 // 默认状况下Optimize都为false,也不建议设置为true,由于会进行一些侵入性的优化 8 // 除非你对cglib的优化很是了解,不然不建议开启 9 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { 10 Class<?> targetClass = config.getTargetClass(); 11 if (targetClass == null) { 12 throw new AopConfigException("TargetSource cannot determine target class: " + 13 "Either an interface or a target is required for proxy creation."); 14 } 15 // 须要注意的是,若是须要代理的类自己就是一个接口 16 // 或者须要被代理的类自己就是一个经过jdk动态代理生成的类 17 // 那么无论如何设置都会使用jdk动态代理 18 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { 19 return new JdkDynamicAopProxy(config); 20 } 21 return new ObjenesisCglibAopProxy(config); 22 } 23 // 不然都是jdk代理 24 else { 25 return new JdkDynamicAopProxy(config); 26 } 27 }
至此完成了代理的建立。
(四)织入
Spring主要使用JDK动态代理,因此先回顾性JDK动态代理的原理(详见上一节JDK动态代理)。
Java动态代理机制中有两个重要的接口和类:
(1)接口InvocationHandler:动态代理类的调用处理程序。
(2)Proxy:动态代理类,Proxy类就是用来建立一个代理对象的类,
Java动态代理的步骤:
一、建立目标类(委托类)的接口
二、建立目标类(委托类)
三、定义一个代理类的调用处理程序。该程序必须实现接口InvocationHandler,且必须实现接口的invoke方法。
四、经过Proxy的静态方法newProxyInstance()建立一个代理对象。
五、经过代理对象调用委托类对象的方法。
其实Proxy类只是一个链接桥,把代理(InvocationHandler)与被代理类关联起来,真正处理事情的是InvocaHandler。InvocationHandler接口中的invoke方法在代理类中是动态实现的,当咱们经过动态代理调用一个方法的时候,这个方法的调用会被转发到到调用处理程序的invoke方法中。
Spring的AOP实现也是用了Proxy和InvocationHandler这两个东西。JDK代理中InvocationHandler的建立是最为核心的。在自定义的InvocationHandler中须要重写3个函数。(1)构造函数,将代理的对象传入。(2)invoke方法,此方法中实现了AOP加强的全部逻辑。(3)getProxy方法。
上面咱们分析了建立代理最终调用了DefaultAopProxyFactory类的createAopProxy方法,若是使用的是JDK动态代理,其代码为return new JdkDynamicAopProxy(config);。 咱们进入JdkDynamicAopProxy类(package org.springframework.aop.framework)。这个类就是用来生成jdk动态代理。能够看到这个类自己就是一个InvocationHandler,这意味着当调用代理对象中的方法时,最终会调用到JdkDynamicAopProxy的invoke方法。
重点看其getProxy函数和invoke函数。
1 public Object getProxy(@Nullable ClassLoader classLoader) { 2 if (logger.isTraceEnabled()) { 3 logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); 4 } 5 // 这里获取到代理类须要实现的全部的接口 6 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); 7 // 须要明确是否在接口定义了hashCode以及equals方法 8 // 若是接口中没有定义,那么在调用代理对象的equals方法的时候 9 // 若是两个对象相等,那么意味着它们的目标对象,通知以及实现的接口都相同 10 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); 11 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 12 }
JDKProxy的使用关键是建立自定义的InvocationHandler,InvocationHandler中包含了须要覆盖的getProxy,上述方法就是完成了这个操做。JdkDynamicAopProxy实现了接口AopProxy、InvocationHandler和Serializable。InvocationHandler除了getProxy还有invoke函数,JdkDynamicAopProxy类将其核心逻辑写在了这个方法中。
1 /** 2 * Implementation of {@code InvocationHandler.invoke}. 3 * <p>Callers will see exactly the exception thrown by the target, 4 * unless a hook method throws an exception. 5 */ 6 @Override 7 @Nullable 8 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 9 Object oldProxy = null; 10 boolean setProxyContext = false; 11 12 TargetSource targetSource = this.advised.targetSource; 13 Object target = null; 14 15 try { 16 // 首先处理的是hashCode跟equals方法,若是接口中没有定义这两个方法,那么会调用本类中定义的equals方法 17 // equals方法的处理。只有当两个类的目标对象,通知以及实现的接口都相等的状况下equals才会返回true 18 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { 19 // The target does not implement the equals(Object) method itself. 20 return equals(args[0]); 21 } 22 //hash方法的处理 23 else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { 24 // The target does not implement the hashCode() method itself. 25 return hashCode(); 26 } 27 // 也就是说咱们调用的是DecoratingProxy这个接口中的方法 28 // 这个接口中只定义了一个getDecoratedClass方法,用于获取到 29 // 最终的目标对象,在方法实现中会经过一个while循环来不断接近 30 // 最终的目标对象,直到获得的目标对象不是一个被代理的对象才会返回 31 else if (method.getDeclaringClass() == DecoratingProxy.class) { 32 // There is only getDecoratedClass() declared -> dispatch to proxy config. 33 return AopProxyUtils.ultimateTargetClass(this.advised); 34 } 35 // 说明调用的是Advised接口中的方法,这里只是单纯的进行反射调用 36 else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && 37 method.getDeclaringClass().isAssignableFrom(Advised.class)) { 38 // Service invocations on ProxyConfig with the proxy config... 39 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); 40 } 41 42 Object retVal; 43 44 //有时候目标对象内部的自我调用将没法实施切面中的加强则须要经过此属性暴露代理 45 // 将代理类暴露到线程上下文中,调用AopContext.setCurrentProxy方法将其放入到一个threadLocal中 46 if (this.advised.exposeProxy) { 47 // Make invocation available if necessary. 48 oldProxy = AopContext.setCurrentProxy(proxy); 49 setProxyContext = true; 50 } 51 52 // 接下来就是真正的执行代理逻辑了 53 target = targetSource.getTarget(); 54 Class<?> targetClass = (target != null ? target.getClass() : null); 55 56 // 获取当前方法的拦截器链 57 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 58 59 if (chain.isEmpty()) { 60 //若是没有发现任何拦截器链那么直接调用切点方法 61 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); 62 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); 63 } 64 // 不然开始执行整个链条 65 else { 66 //将拦截器封装在ReflectiveMethodInvocation以便于使用期proceed进行连接表用拦截器 67 MethodInvocation invocation = 68 new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); 69 //执行拦截器链 70 retVal = invocation.proceed(); 71 } 72 73 // Massage return value if necessary. 74 // 这里是处理一种特殊状况,就是当执行的方法返回值为this的状况 75 // 这种状况下,须要返回当前的代理对象而不是目标对象 76 Class<?> returnType = method.getReturnType(); 77 if (retVal != null && retVal == target && 78 returnType != Object.class && returnType.isInstance(proxy) && 79 !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { 80 // Special case: it returned "this" and the return type of the method 81 // is type-compatible. Note that we can't help if the target sets 82 // a reference to itself in another returned object. 83 retVal = proxy; 84 } 85 else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { 86 throw new AopInvocationException( 87 "Null return value from advice does not match primitive return type for: " + method); 88 } 89 return retVal; 90 } 91 finally { 92 if (target != null && !targetSource.isStatic()) { 93 // Must have come from TargetSource. 94 targetSource.releaseTarget(target); 95 } 96 if (setProxyContext) { 97 // Restore old proxy. 98 AopContext.setCurrentProxy(oldProxy); 99 } 100 } 101 }
上面的函数最主要的工做是建立了一个拦截器链,并使用ReflectiveMethodInvocation类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中实现了拦截器的逐一调用。咱们继续看proceed方法是怎么实现前置加强在目标方法前调用,后置加强在目标方法后调用的逻辑。
ReflectiveMethodInvocation(package org.springframework.aop.framework包中)是一个核心类,激发拦截链工做实现。该类实现了aop联盟的MethodInvocation,间接实现了Invocation和Joinpoint。咱们进入其proceed函数:
1 @Override 2 @Nullable 3 public Object proceed() throws Throwable { 4 // We start with an index of -1 and increment early. 5 //执行完全部加强后执行切点方法 6 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { 7 return invokeJoinpoint(); 8 } 9 10 //获取下一个要执行的拦截器 11 Object interceptorOrInterceptionAdvice = 12 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 13 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { 14 // Evaluate dynamic method matcher here: static part will already have 15 // been evaluated and found to match. 16 //动态匹配 17 InterceptorAndDynamicMethodMatcher dm = 18 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 19 Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); 20 if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { 21 return dm.interceptor.invoke(this); 22 } 23 else { 24 // Dynamic matching failed. 25 // Skip this interceptor and invoke the next in the chain. 26 //不匹配就不执行拦截器 27 return proceed(); 28 } 29 } 30 else { 31 // It's an interceptor, so we just invoke it: The pointcut will have 32 // been evaluated statically before this object was constructed. 33 //普通拦截器,直接调用拦截器。将this做为参赛传入以保障当前实例中调用链的执行。 34 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 35 } 36 }
在proceed方法中,ReflectiveMethodInvocation的主要职责是维护了调用的计数器,记录着当前调用连接的位置,以即可以有序的进行下去。
本文参考了 郝佳《Spring源码深度解析》第七章AOP及博客园、CSDN部分文献。
博众家之所长,集群英之荟萃。遴选各IT领域精品雄文!
欢迎关注“IT架构精选”