AOP 的几个概念
名称 | 解释 |
---|---|
Pointcut | 切点,决定处理如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为execution方式和annotation方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。 |
Advice | 增强,包括处理时机和处理内容。处理内容就是要做什么事,比如校验权限和记录日志。处理时机就是在什么时机执行处理内容,分为前置处理(即业务代码执行前)、后置处理(业务代码执行后)等。 |
Aspect | 切面,即,Pointcut 和 Advice。 |
Joint point | 接入点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行 |
Weaving | 织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。 |
增强类型
- 前置通知(Before Advice)
在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在
<aop:aspect>
里面使用<aop:before>
元素进行声明。
- 后置通知(After Advice)
当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext 中在
<aop:aspect>
里面使用<aop:after>
元素进行声明。
- 返回后通知(After Return Advice)
在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext 中在
<aop:aspect>
里面使用<after-returning>
元素进行声明。
- 异常通知(After Throwing Advice)
在 方 法 抛 出 异 常 退 出 时 执 行 的 通 知 。 ApplicationContext 中 在
<aop:aspect>
里 面 使 用<aop:after-throwing>
元素进行声明。
- 环绕通知(Around Advice)
包围一个连接点的通知,类似 Web 中 Servlet 规范中的 Filter 的 doFilter 方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext 中在
<aop:aspect>
里面使用<aop:around>
元素进行声明。例如,ServiceAspect 中的 around 方法。
JoinPoint 和 ProceedingJoinPoint 的关系
AspectJ 使用
org.aspectj.lang.JoinPoint
接口表示目标类连接点对象,如果是环绕增强时,使用org.aspectj.lang.ProceedingJoinPoint
表示连接点对象,该类是JoinPoint的子接口。任何一个增强方法都可以通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。
在增强(advice)方法中可以声明一个
JoinPoint
类型的参数, 通过JoinPoint可以访问连接点的细节。
JoinPoint
JoinPoint
对象封装了SpringAop中切面方法的信息, 在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息:
-
切入点的方法名字及其参数;
-
切入点方法标注的注解对象(通过该对象可以获取注解信息);
-
切入点目标对象(可以通过反射获取对象的类名,属性和方法名)。
例如:
/**
* 切点:
* 定义一个切入点表达式,用来确定哪些类需要代理
* 代表com.gitee.tangmonkmeat.common.service包下UserService类的create*方法都会被代理
*/
@Pointcut("execution(* com.gitee.tangmonkmeat.common.service.UserService.create*(..))")
public void create(){}
/**
* 前置增强:在目标方法执行前执行
*/
@Before(value = "create()")
public void before(JoinPoint joinPoint){
System.out.println("【" +joinPoint.getSignature().getName() + "】方法执行,参数是:" + Arrays.asList(joinPoint.getArgs()));
System.out.println(joinPoint.getSignature());
System.out.println("目标方法名为:" + joinPoint.getSignature().getName());
System.out.println("目标方法所属类的简单类名:" + joinPoint.getSignature().getDeclaringType().getSimpleName());
System.out.println("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
System.out.println("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
System.out.println(Arrays.toString(joinPoint.getArgs()));
System.out.println(joinPoint.getKind());
System.out.println(joinPoint.getSourceLocation());
System.out.println(joinPoint.getStaticPart());
System.out.println(joinPoint.getTarget());
System.out.println(joinPoint.getThis());
}
输出如下:
【createUser】方法执行,参数是:[八戒, 100]
User com.gitee.tangmonkmeat.common.service.UserService.createUser(String,int)
目标方法名为:createUser
目标方法所属类的简单类名:UserService
目标方法所属类的类名:com.gitee.tangmonkmeat.common.service.UserService
目标方法声明类型:public abstract
[八戒, 100]
method-execution
org.springframework.aop.aspectj.
MethodInvocationProceedingJoinPoint$SourceLocationImpl@2101b44a
execution(User com.gitee.tangmonkmeat.common.service.UserService.createUser(String,int))
com.gitee.tangmonkmeat.common.service.impl.UserServiceImpl@2cc3ad05
com.gitee.tangmonkmeat.common.service.impl.UserServiceImpl@2cc3ad05
常用 api
方法名 | 功能 |
---|---|
Signature getSignature(); | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs(); | 获取传入目标方法的参数对象 |
Object getTarget(); | 获取被代理的对象 |
Object getThis(); | 获取代理对象 |
ProceedingJoinPoint
ProceedingJoinPoint
继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法
方法名 | 功能 |
---|---|
Object proceed() throws Throwable | 通过反射执行目标对象的连接点处的方法 |
Object proceed(java.lang.Object[] args) throws Throwable | 通过反射执行目标对象连接点处的方法,不过使用新的参数替换原来的参数 |
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69744.html