AOP术语SpringAOP
Posted 保护眼睛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AOP术语SpringAOP相关的知识,希望对你有一定的参考价值。
AOP术语、SpringAOP
AOP中的相关术语
官方
Aspect: A modularization of a concern that cuts across multiple classes. Transaction management is a good example of a crosscutting concern in enterprise Java applications. In Spring AOP, aspects are implemented by using regular classes (the schema-based approach) or regular classes annotated with the @Aspect annotation (the @AspectJ style).
Join point: A point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.
Advice: Action taken by an aspect at a particular join point. Different types of advice include “around”, “before” and “after” advice. (Advice types are discussed later.) Many AOP frameworks, including Spring, model an advice as an interceptor and maintain a chain of interceptors around the join point.
Pointcut: A predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default.
Introduction: Declaring additional methods or fields on behalf of a type. Spring AOP lets you introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a bean implement an IsModified interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)
Target object: An object being advised by one or more aspects. Also referred to as the “advised object”. Since Spring AOP is implemented by using runtime proxies, this object is always a proxied object.
AOP proxy: An object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy is a JDK dynamic proxy or a CGLIB proxy.
Weaving: linking aspects with other application types or objects to create an advised object. This can be done at compile time (using the AspectJ compiler, for example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs weaving at runtime.
通知、增强处理(Advice) 就是抽取出来的通用功能,也就是安全、事物、日志等。你给先定义好,然后在需要的地方引用。
连接点(JoinPoint) 应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
在 Spring AOP 中,Join Point 总是方法的执行点, 即只有方法连接点。所以使用SpringAOP,无需使用
连接点的代码。就是spring允许你引用通知(Advice)的地方,那可就真多了,基本每个方法的前、后以及前后都包括,或抛出异常时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你将构造器、属性注入作为连接点。不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点,也就是可以引入通知的地方都是连接点。
切点(Pointcut)在 Spring 中, 所有的方法都可以认为是 Join Point,但是我们并不希望在所有的方法上都添加 Advice, 而 Pointcut 的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述)来匹配Join Point,给满足规则的 Join Point 添加 Advice。 上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有十几个连接点了对吧,但是你并不想在所有方法附近都使用通知(使用叫织入),你只是想让其中几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中你想要引入通知的方法。
切面(Aspect)切面(Aspect)由 切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包括了连接点的定义。Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
在SpringAOP中,切面由容器中的Bean使用@Aspect注解实现 切面是通知和切入点的结合。连接点是为了让你好理解切点搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的befor,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
织入(Weaving):织入是将增强添加到目标类具体连接点上的过程,AOP有三种织入方式:①编译期织入:需要特殊的Java编译期(例如AspectJ的ajc);②装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;③运行时织入:在运行时为目标类生成代理实现增强。Spring采用了动态代理的方式实现了运行时织入,而AspectJ采用了编译期织入和装载期织入的方式。
目标对象:被一个或者多个切面所通知(Advice)的对象,也把它叫做被通知的对象(Advised)。既然SpringAOP是通过运行时代理实现的,那么这个对象永远是一个被代理(Proxied)对象。
SpringAOP中的实现
Spring AOP由 spring-aop 、 spring-aspects 和 spring-instrument 3 个模块组成。
SpringAOP构建在动态代理基础上,因此Spring对AOP的支持局限于方法拦截。
SpringAOP支持 JDK 和 CGLIB 方式实现动态代理。默认情况下,实现了接口的类,使用 AOP 会基于JDK 生成代理类,没有实现接口的类,会基于 CGLIB 生成代理类。
Spring对AOP的支持
基于代理的经典 AOP;
@AspectJ 注解驱动的切面;
纯 POJO 切面;
注入式 AspectJ 切面; Spring
通过在代理类中织入包裹切面,Spring 在运行期间将切面织入到 Spring 管理的 Bean 中。
代理类封装了目标类,并拦截被通知的方法调用,再将调用转发给真正的目标 Bean
当拦截到方法调用时,在调用目标 Bean 方法之前,代理会执行切面逻辑。
当真正应用需要被代理的 Bean 时,Spring 才创建代理对象。如果使用 ApplicationContext,在 ApplicationContext 从 BeanFactory 中加载所有 Bean 时,Spring 创建代理对象,因为 Spring 在运行时候创建代理对象,所以我们不需要特殊的编译器来织入 Spring AOP 的切面。
Spring 支持方法创建连接点
因为 Spring 基于动态代理,所以 Spring 只支持方法连接点。
Spring 缺失对字段连接点的支持,无法让我们更加细粒度的通知,例如拦截对象字段的修改
Spring 缺失对构造器连接点支持,在 Bean 创建时候进行通知。
示例
切点表达式、切点
在 Spring AOP 中,需要使用 AspectJ 的切点表达式来定义切点。
具体可以参考这篇
@AspectJ 支持三种通配符
* :匹配任意字符,只匹配一个元素(包,类,或方法,方法参数)
.. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使用。
+ :表示按照类型匹配指定类的所有类,必须跟在类名后面,如 com.cad.Car+ ,表示继承该类的所有子类包括本身
切点表达式由切点函数组成,其中 execution() 是最常用的切点函数,用来匹配方法,语法为:
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)
修饰符和异常可以省略
表达式示例
execution(* com.cad.demo.User.(…)) :匹配 User 类里的所有方法
execution( com.cad.demo.User+.(…)) :匹配该类的子类包括该类的所有方法
execution( com.cad..(…)) :匹配 com.cad 包下的所有类的所有方法
execution(* com.cad….(…)) :匹配 com.cad 包下、子孙包下所有类的所有方法
execution(* addUser(String, int)) :匹配 addUser 方法,且第一个参数类型是 String,第二个
参数类型是 int
匹配com.example.demo.controller包下的UserController类的所有方法
切面
增强通知
前置通知
使用@Before:通知方法会在目标方法调用之前执行。
后置通知
使用@After:通知方法会在目标方法返回或者抛出异常后调用。
返回之后通知
使用@AfterReturning:通知方法会在目标方法返回后调用。
抛异常后通知
使用@AfterThrowing:通知方法会在目标方法抛出异常后调用。
环绕通知
使用@Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行
为。
//2.添加通知
@Before("pointcut()")
public void doBefore()
System.out.println("执行了切面的前置通知");
//3.添加后置通知
@After("pointcut()")
public void doAfter()
System.out.println("执行了切面的后置通知");
//添加在return之前的通知方法
@AfterReturning("pointcut()")
public void doAfterReturn()
System.out.println("执行了在return之前的通知");
//添加在抛出异常之前的通知方法
@AfterThrowing("pointcut()")
public void doThrowing()
System.out.println("执行了在抛出异常之前的通知");
//环绕通知
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint)
System.out.println("进行了环绕通知:方法执行之前");
Object res = null;
//执行被代理的方法
try
res = joinPoint.proceed();
catch (Throwable throwable)
throwable.printStackTrace();
System.out.println("执行l环绕通知:执行了方法调用之后");
return res;
织入
织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。
在目标对象的生命周期里有多个点可以进行织入:
编译期:
切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载器:
切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标
类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving. LTW)就支持以这种方式织入切面。
运行期:
切面在应用运行的某一时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建
一个代理对象。SpringAOP就是以这种方式织入切面的。
目标对象
结果
以上是关于AOP术语SpringAOP的主要内容,如果未能解决你的问题,请参考以下文章
SpringAOP底层原理(动态代理)-》 AOP概念及术语 -》 AOP实现