一. 在pom.xml中加入依赖
<!-- 整合AOP start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 整合AOP end -->
二. 编写AOP切面
创建SpringBootAop.java 使用@Component和@Aspect注解修饰:
(前置通知)
package online.bendou.aop;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@Component
@Aspect
public class SpringBootAop {
// 配置切点
// 拦截online.bendou.controller包及其子包下的所有类的所有方法,也拦截@RequestMapping注解修饰的方法
@Pointcut("execution(* online.bendou.controller..*.*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void executeMethod(){
}
/**
* 前置通知:
* 看executeMethod()切点的拦截可知:
* 拦截online.bendou.controller包及其子包下的所有类的所有方法, 和@RequestMapping注解修饰的方法
* 所以下面的@Before("executeMethod")就相当于:@Before("execution(* online.bendou.controller..*.*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)")
*/
@Before("executeMethod()")
public void doBeforeAdvice(JoinPoint joinPoint){
System.out.println("这是前置通知!");
// 通过joinPoint获得信息
// 拦截的方法名
System.out.println("1:"+joinPoint.getSignature().getName());
// 执行的通知种类
System.out.println("2:"+joinPoint.getKind());
// 拦截的方法的参数
System.out.println("3:"+joinPoint.getArgs());
// 拦截的目标类
System.out.println("4:"+joinPoint.getTarget().toString());
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request= (HttpServletRequest) attributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
// 请求方式
System.out.println("method:"+request.getMethod());
// 请求ip
System.out.println("remoteAddr:"+request.getRemoteAddr());
// 请求路径
System.out.println("servletPath:"+request.getServletPath());
// 请求参数
Enumeration<String> parameterNames = request.getParameterNames();
while(parameterNames.hasMoreElements()){
String element = parameterNames.nextElement();
System.out.println(element+"---"+request.getParameter(element));
}
}
注:
① 通过JoinPoint可以获得通知的签名信息, 如目标方法名, 目标方法参数等;
② 通过RequestContextHolder来获取请求信息, Session信息等;
(后置返回通知)
package online.bendou.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class SpringBootAop {
/**
* 后置通知:
* 拦截@GetMapping注解修饰的方法
*
* returning: 拦截方法执行后的返回值
*/
@AfterReturning(value="@annotation(org.springframework.web.bind.annotation.GetMapping)",returning="value")
public void doAfterAdvice(JoinPoint joinPoint, Object value){
System.out.println("后置通知执行了!");
System.out.println("拦截的目标方法名:"+joinPoint.getSignature().getName());
System.out.println(value);
}
}
(后置异常通知)
package online.bendou.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class SpringBootAop {
/**
* 后置异常通知:
* 拦截online.bendou.controller包及其子包下的所有类的所有方法中出现的异常
* throwing 限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行
*/
@AfterThrowing(throwing="exception",value="execution(* online.bendou.controller..*.*(..))")
public void doAfterThrowingAdvice(JoinPoint joinPoint, Throwable exception){
System.out.println("出现异常了!");
if(exception instanceof NullPointerException){
System.out.println("空指针了!");
}
}
}
(后置最终通知)
package online.bendou.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class SpringBootAop {
/**
* 后置最终通知
* 拦截@RequestMapping注解修饰的方法
*/
@After("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void doAfterAdvice(JoinPoint joinPoint){
System.out.println("拦截的目标方法名:"+joinPoint.getSignature().getName());
System.out.println("后置最终通知执行了!");
}
}
(环绕通知)
这个比较厉害:
① 统计方法运行时间
② 控制是否执行目标方法,不执行返回null
③ 替换请求参数
④ 替换返回数据
package online.bendou.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class SpringBootAop {
/**
* 环绕通知
* 拦截online.bendou.controller包及其子包下的所有类的所有方法
*环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
*环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
*/
@Around("execution(* online.bendou.controller..*.*(..))")
public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("环绕通知执行了!");
System.out.println("拦截的目标方法名:"+proceedingJoinPoint.getSignature().getName());
try {
// 执行
Object proceed = proceedingJoinPoint.proceed();
// 替换请求参数
Object proceed2 = proceedingJoinPoint.proceed(new Object[]{"王玉洁,19"});
// return proceed;
return proceed2;
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 不执行目标方法的话, 返回null
return null;
}
}