AOP面向切面编程是Aspect Oriented Programming的缩写,主要通过预编译方式和动态代理实现程序功能。
以下主要讲五点内容
- 创建SpringBoot AOP
- AOP注解解析
- Pointcut Expression切点表达式
- AOP做切面统一处理Web请求日志
- AOP切面的优先级
1. 创建SpringBoot AOP
1.1 New Project 创建工程(jdk1.8,默认url)
1.2 填写工程名( 这里用aop)
1.3 选择Aspects和Web依赖
1.4 点击Next–>点击Finish
1.5 pom.xml文件中已添加Aspects和web依赖
注意:在完成了引入AOP依赖包后,不需要去做其他配置。无需在主程序类添加代理注解@EnableAspectJAutoProxy来启用,因为AOP的默认配置属性,其中spring.aop.auto属性默认是开启的既spring.aop.auto=true,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy代理注解。
2. AOP注解解析
-
使用@Aspect注解将一个java类定义为切面类
-
使用@Pointcut定义一个切入点,参数为切点表达式
-
使用@Before在切入点前切入内容
-
使用@After在切入点后切入内容
-
使用@AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
-
使用@Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容
-
使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑
3. Pointcut Expression切点表达式
- designators指示器
- execution( ) 匹配方法
- @target( ) 匹配注解
- @args( ) 匹配注解
- @within( ) 匹配注解
- @annotation( ) 匹配注解
- within( ) 匹配包/类型
- this( ) 匹配对象
- bean( ) 匹配对象
- target( ) 匹配对象
- args( ) 匹配参数
- wildcards通配符
- 星号 * 匹配任意数量字符
- 加号 + 匹配指定类及其子类
- 两点 . . 匹配任意数子包/参数
- operators操作符
- 与操作符 &&
- 或操作符 ||
- 非操作符!
4. AOP做切面统一处理Web请求日志
package com.xyz.aop.config;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
/**
* @Description: web日志切面配置类
* @Date: 2018/9/20 17:00
* @Author: xyz
*/
@Aspect //将此类定义为切面类
@Component // 将此类纳入spring中管理
public class WebLogAspectConfig {
private Logger logger = LoggerFactory.getLogger(this.getClass());
// 定义切点LoginController类下的所有方法
@Pointcut("execution(public * com.xyz.aop.controller.LoginController.*(..))")// 修饰符 返回值类型 包名 类名 方法名(参数)
public void WebLog(){
}
// 在切点前切入
@Before("WebLog()")
public void doBefore(JoinPoint joinPoint){
// 获取请求的内容
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
// 用日志记录请求内容
logger.info("请求URL:"+request.getRequestURL().toString());
logger.info("请求方法HTTP_METHOD:"+request.getMethod());
logger.info("请求IP:"+request.getRemoteAddr());
// 请求的类名方法名
logger.info("请求CLASS_METHOD :"+joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
// 请求方法的参数
logger.info("请求参数Args:"+ Arrays.toString(joinPoint.getArgs()));
}
// 请求结束后返回的内容
@AfterReturning(returning ="object",pointcut = "WebLog()")
public void doAfterReturning(Object object){
logger.info("返回内容:"+object);
}
}
package com.xyz.aop.controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description: 登入
* @Date: 2018/9/20 17:42
* @Author: xyz
*/
@RestController
public class LoginController {
@PostMapping(value = "/login")
public String login(@RequestParam String name){
return "LoginName="+name;
}
}
5. AOP优先级
- @Order(i)注解来标识切面的优先级。i的值越小,优先级越高
- 在切入点前的操作,按order的值由小到大执行
- 在切入点后的操作,按order的值由大到小执行