SpringBoot学习-(九)SpringBoot中的AOP
来源:互联网 发布:js cookie 跨域 编辑:程序博客网 时间:2024/06/08 05:08
AOP相关概念:
- Target(目标对象):需要被代理增强的对象
- Proxy(代理对象):目标对象被AOP 织入 增强/通知后,产生的对象.
- Joinpoint(连接点):指那些被拦截到的点.在Spring中,这些点指方法(因为Spring只支持方法类型的连接点).
- Pointcut(切入点):指需要(配置)被增强的Joinpoint.
- Advice(通知/增强):指拦截到Joinpoint后要做的操作.通知分为前置通知/后置通知/异常通知/最终通知/环绕通知等.
- Aspect(切面):切入点和通知的结合。
- Weaving(织入):指把增强/通知应用到目标对象来创建代理对象的过程(Spring采用动态代理织入,AspectJ采用编译期织入和类装载期织入).
- Introduction(引入增强):一种特殊通知,在不修改类代码的前提下,可以在运行期为类动态地添加一些Method/Field(不常用).
AOP相关注解:
- @Aspect注解将一个java类定义为切面类
- @Pointcut定义一个切入点,可以是一个规则表达式
- @Before在切入点开始处切入内容
- @After在切入点结尾处切入内容
- @AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
- @AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑
- @Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容
1.添加pom依赖
<!-- springboot aop --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId></dependency>
starter中默认添加了@EnableAspectJAutoProxy
2.编写切面类
package com.ahut.aop;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;/** * * @ClassName: ActionAspect * @Description:控制层切面类 * @author cheng * @date 2017年9月25日 上午11:05:38 */@Aspect@Componentpublic class ActionAspect { /** * * @Title: actionAspect * @Description:切入点表达式 */ @Pointcut("execution(public * com.ahut.action.*.*(..))") public void actionAspect() { } /** * * @Title: beforeMethod * @Description:目标方法执行之前调用 */ @Before("actionAspect()") public void beforeMethod() { System.out.println("目标方法执行之前调用。。。"); } /** * * @Title: afterMethod * @Description:目标方法返回或者抛出异常之后调用 */ @After("actionAspect()") public void afterMethod() { System.out.println("目标方法返回或者抛出异常之后调用。。。"); } /** * * @Title: afterReturningMethod * @Description:目标方法返回之后调用,抛出异常时不调用 */ @AfterReturning("actionAspect()") public void afterReturningMethod() { System.out.println("目标方法返回之后调用,抛出异常时不调用。。。"); } /** * * @Title: afterThrowingMethod * @Description:目标方法抛出异常之后调用,正常返回时不调用 */ @AfterThrowing("actionAspect()") public void afterThrowingMethod() { System.out.println("目标方法抛出异常之后调用,正常返回时不调用。。。"); } /** * * @Title: aroundMethod * @Description: 环绕通知 * @param joinPoint * @return * @throws Throwable */ @Around("actionAspect()") public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕在目标方法之前。。。"); // 访问目标方法名称 String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); // 访问目标方法的参数 Object[] paramsArr = joinPoint.getArgs(); // 执行目标方法 Object returnObj = joinPoint.proceed(paramsArr); System.out.println("执行的方法:" + methodName); System.out.println("环绕在目标方法之后。。。"); return returnObj; }}
3.执行结果
环绕在目标方法之前。。。目标方法执行之前调用。。。执行的方法:com.ahut.action.GoodsTypeAction.getGoodsTypeList环绕在目标方法之后。。。目标方法返回或者抛出异常之后调用。。。目标方法返回之后调用,抛出异常时不调用。。。
JoinPoint详解
AspectJ使用org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用org.aspectj.lang.ProceedingJoinPoint表示连接点对象,该类是JoinPoint的子接口。任何一个增强方法都可以通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。我们先来了解一下这两个接口的主要方法:
1)JoinPoint
- java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
- Signature getSignature() :获取连接点的方法签名对象;
- java.lang.Object getTarget() :获取连接点所在的目标对象;
- java.lang.Object getThis() :获取代理对象本身;
2)ProceedingJoinPoint
ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法:
- java.lang.Object proceed() throws java.lang.Throwable:通过反射执行目标对象的连接点处的方法;
- java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参。
常用的几个:
//获取目标方法所在类名称String className = joinPoint.getSignature().getDeclaringTypeName()//获取目标方法名称String methodName = joinPoint.getSignature().getName();//获取目标方法完整名称String fullMethodName = className + "." + methodName;//获取目标方法参数Object[] paramsArray = joinPoint.getArgs();//以原来的参数列表执行目标方法Object returnObject = joinPoint.proceed();//以自定义参数列表执行目标方法Object returnObject = joinPoint.proceed(paramsArray);
关于多个切面的执行顺序
由于通过AOP实现,程序得到了很好的解耦,但是也会带来一些问题,比如:我们可能会对Web层做多个切面,校验用户,校验头信息等等,这个时候经常会碰到切面的处理顺序问题。
所以要定义每个切面的优先级,我们需要@Order(i)-(直接添加在切面类上)注解来标识切面的优先级。
i值越小,优先级越高。
假设我们还有一个切面是CheckNameAspect用来校验name必须为jack,我们为其设置@Order(10),而上文中WebLogAspect设置为@Order(5),所以WebLogAspect有更高的优先级,这个时候执行顺序是这样的:
在@Before中优先执行@Order(5)的内容,再执行@Order(10)的内容
在@After和@AfterReturning中优先执行@Order(10)的内容,再执行@Order(5)的内容
创建两个相似的ActionAspect, 代码执行结果:
环绕在目标方法之前。。。111目标方法执行之前调用。。。111环绕在目标方法之前。。。222目标方法执行之前调用。。。222//切入点环绕在目标方法之后。。。222目标方法返回或者抛出异常之后调用。。。222目标方法返回之后调用,抛出异常时不调用。。。222环绕在目标方法之后。。。111目标方法返回或者抛出异常之后调用。。。111目标方法返回之后调用,抛出异常时不调用。。。111
所以我们可以这样子总结:
- 在切入点前的操作,按order的值由小到大执行
- 在切入点后的操作,按order的值由大到小执行
- SpringBoot学习-(九)SpringBoot中的AOP
- SpringBoot学习-(八)SpringBoot中的新注解
- springboot学习(7)springboot使用AOP打印日志信息
- (7)学习SpringBoot 之 AOP
- SpringBoot学习-(五)SpringBoot测试
- SpringBoot学习-(十一)SpringBoot过滤器
- springboot-AOP
- springboot-AOP
- SpringBoot-AOP
- springBoot aop
- SpringBoot 学习记录(九): Email
- SpringBoot学习-(二)SpringBoot注解和配置
- SpringBoot学习-(三)SpringBoot开发Web
- SpringBoot学习-(四)SpringBoot配置Druid连接池
- SpringBoot学习-(六)SpringBoot与Mybatis整合
- SpringBoot学习-(七)SpringBoot分页插件PageHelper
- SpringBoot学习-(十)SpringBoot日志处理
- SpringBoot学习-(十二)SpringBoot中建立WebSocket连接
- JS中appendChild问题
- A+B
- deeplearn.js入门
- 如何使用Android Studio把自己的Android library分享到jCenter和Maven Central
- Java不同类型字符转换String/int/Float/////
- SpringBoot学习-(九)SpringBoot中的AOP
- String,对象,Map,json互转封装类
- 数据结构—线性表—八进制数加法
- [ReactNative]ViewPager不显示图片
- cakes
- ajax response 导出文件
- 机器学习实践-k近邻算法-约会网站配对源码
- can't start git:usr/bin/git
- 通过函数给指针申请内存时遇到的内存泄漏问题