AOP这个名词相信大家都不陌生,尤其是在面试的过程中,面试官多多少少都会问到一些关于他的问题,这玩意儿有用吗?答案是必然的,只是在日常业务逻辑中用的不多,一般像想在某个写好的代码之前插入一些内容,这种情况下用的比较多,那么接下来我们就一起来看看他在spring boot中的使用。
项目结构如下:
1.新建项目,pom如下:
引入如下jar包即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.新建WebLogAspect类
在完成了引入AOP依赖包后,一般来说并不需要去做其他配置。也许在Spring中使用过注解配置方式的人会问是否需要在程序主类中增加@EnableAspectJAutoProxy
来启用,实际并不需要
package com.gwd.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
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;
/**
* @FileName WebLogAspect.java
* @Description:TODO
* @author JackHisen(gu.weidong)
* @version V1.0
* @createtime 2018年2月27日 上午9:32:17
* 修改历史:
* 时间 作者 版本 描述
*====================================================
*
*/
@Component
@Aspect
public class WebLogAspect {
@Pointcut("execution(public * com.gwd.web..*.*(..))")
public void weblog() {}
@Before("weblog()")
public void webBefore() {
System.out.println("在更新之前");
System.out.println("stop");
return;
}
@After("weblog()")
public void webAfter() {
System.out.println("在更新之后");
}
@Around("weblog()")
public void webAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知前……");
pjp.proceed();
System.out.println("环绕通知后……");
}
@AfterReturning("weblog()")
public void webAfterReturn() {
System.out.println("afterReturning ……");
}
}
实现AOP的切面主要有以下几个要素:
使用@Aspect注解将一个java类定义为切面类
使用@Pointcut定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。
根据需要在切入点不同位置的切入内容
使用@Before在切入点开始处切入内容
使用@After在切入点结尾处切入内容
使用@AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
使用@Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容
使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑
3.controller
package com.gwd.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @FileName TestController.java
* @Description:TODO
* @author JackHisen(gu.weidong)
* @version V1.0
* @createtime 2018年2月27日 上午10:03:26
* 修改历史:
* 时间 作者 版本 描述
*====================================================
*
*/
@RestController
public class TestController {
@RequestMapping("/testAop")
public void testAop() {
System.out.println("test进行中");
}
}
4.测试结果如下
环绕通知前……
在更新之前
stop
test进行中
环绕通知后……
在更新之后
afterReturning ……
在一个方法只被一个aspect类拦截时,aspect类内部的 advice 将按照以下的顺序进行执行:
正常情况:
异常情况:
优化:AOP切面的优先级
由于通过AOP实现,程序得到了很好的解耦,但是也会带来一些问题,比如:我们可能会对Web层做多个切面,校验用户,校验头信息等等,这个时候经常会碰到切面的处理顺序问题。
所以,我们需要定义每个切面的优先级,我们需要@Order(i)
注解来标识切面的优先级。i的值越小,优先级越高。假设我们还有一个切面是CheckNameAspect
用来校验name必须为didi,我们为其设置@Order(10)
,而上文中WebLogAspect设置为@Order(5)
,所以WebLogAspect有更高的优先级,这个时候执行顺序是这样的:
- 在
@Before
中优先执行@Order(5)
的内容,再执行@Order(10)
的内容 - 在
@After
和@AfterReturning
中优先执行@Order(10)
的内容,再执行@Order(5)
的内容
所以我们可以这样子总结:
- 在切入点前的操作,按order的值由小到大执行
- 在切入点后的操作,按order的值由大到小执行