<!-- Springboot的AOP包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@RestController
public class HelloWorldAOPController {
private Logger log = LoggerFactory.getLogger(HelloWorldAOPController.class);
/**
* hello请求测试 实例:http://localhost:8081/hello?name=world
* @param name 打招呼的姓名
* @return 返回打招呼的整体语句
*/
@RequestMapping("/hello")
public String hello(String name){
StringBuffer hellos = new StringBuffer();
hellos.append("Hello ");
hellos.append(name);
return hellos.toString();
}
}
@Aspect
@Component
@Order(1)
public class WebTimeAspect {
private Logger log = LoggerFactory.getLogger(WebTimeAspect.class);
/**
* 声明一个线程,用于记录请求与响应整个周期期间在服务端消耗的时间
*/
private ThreadLocal<Long> startTime = new ThreadLocal<>();
/**
* 在请求响应之前,即请求到达当前服务端
* 所有demo3下的controller均经过该切面
* @param joinPoint
*/
@Before("within(com.cnhuashao.rapiddevelopment.core..*.*)")
public void doBefore(JoinPoint joinPoint){
log.info("----------- WebTimeAspect doBefore -----------------------------------------");
startTime.set(System.currentTimeMillis());
}
/**
* 在请求响应之后,即请求已经经过controller处理返回后
* @param rvt
*/
@AfterReturning(value = "within(com.cnhuashao.rapiddevelopment.core..*.*)",returning = "rvt")
public void doAfterReturning(Object rvt){
log.info("-----------Start WebTimeAspect doAfterReturning ------");
log.info("本次处理请求耗费时间 : {}",(System.currentTimeMillis() - startTime.get()));
log.info("-----------End WebTimeAspect doAfterReturning -------------------------------");
}
}
访问地址:http://localhost:8081/hello?name=cnHuaShao
image.png
@Aspect
@Component
@Order(2)
public class WebLogAspect {
private Logger log = LoggerFactory.getLogger(WebLogAspect.class);
/**
* 访问localhost时打印的IP地址
*/
private static final String IP_LOCALHOST ="0:0:0:0:0:0:0:1";
/**
* com.cnhuashao.rapiddevelopment.core包及所有子包下任何类的任何方法
*/
@Pointcut("execution(* com.cnhuashao.rapiddevelopment.core..*.*(..))")
public void webLog(){
}
/**
* 在请求响应之前,即请求到达当前服务端
* 所有demo3下的controller均经过该切面
* @param joinPoint
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint){
log.info(" ---------- WebLogAspect doBefore --------------");
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//在系统启动时拦截器经过该位置时会触发空指针异常,这里需要进行非空判断
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
log.info(" 地址: {}", request.getRequestURL().toString());
log.info(" 请求方式: ", request.getMethod());
String ip = request.getRemoteAddr();
if (!IP_LOCALHOST.equals(ip)){
log.info(" 客户端IP: {}", ip);
}
log.info(" 请求参数: {}" + Arrays.toString(joinPoint.getArgs()));
}
}
/**
* 在请求响应之后,即请求已经经过controller处理返回后
* @param rvt
*/
@AfterReturning(pointcut = "webLog()",returning = "rvt")
public void doAfterReturning(Object rvt){
log.info(" ------------Start WebLogAspect doAfterReturning ------");
log.info(" 响应结果 : {}",rvt.toString());
log.info(" ------------End WebLogAspect doAfterReturning ------");
}
/**
* 异常切入
* @param error
*/
@AfterThrowing(pointcut = "webLog()",throwing = "error")
public void doAfterThrowing(Throwable error){
log.error(" ------------Start WebLogAspect doAfterThrowing ------");
log.error("请求处理过程中发生异常:{}",error.getMessage());
log.error(" ------------Start WebLogAspect doAfterThrowing ------");
}
}
访问地址:http://localhost:8081/hello?name=cnHuaShao
image.png
至此已经实现访问时间与日志的切面,里面有一些优化还需要更改一下
在上述代码中每个方法头均有一个切入扫描的包路径,这样在我们日常使用配置时无法统一化管理,为了解决该问题,特将这种统一的全局值提出来。 更改WebTimeAspect类如下
@Aspect
@Component
@Order(1)
public class WebTimeAspect {
private Logger log = LoggerFactory.getLogger(WebTimeAspect.class);
/**
* 声明一个线程,用于记录请求与响应整个周期期间在服务端消耗的时间
*/
private ThreadLocal<Long> startTime = new ThreadLocal<>();
/**
* com.cnhuashao.rapiddevelopment.core包及所有子包下任何类的任何方法
*/
@Pointcut("execution(* com.cnhuashao.rapiddevelopment.core..*.*(..))")
public void webTime(){
}
/**
* 在请求响应之前,即请求到达当前服务端
* 所有demo3下的controller均经过该切面
* 暂存:@Before("within(com.cnhuashao.rapiddevelopment.core..*.*)")
* @param joinPoint
*/
@Before("webTime()")
public void doBefore(JoinPoint joinPoint){
log.info("----------- WebTimeAspect doBefore -----------------------------------------");
startTime.set(System.currentTimeMillis());
}
/**
* 在请求响应之后,即请求已经经过controller处理返回后
* 暂存:@AfterReturning(value = "within(com.cnhuashao.rapiddevelopment.core..*.*)",returning = "rvt")
* @param rvt
*/
@AfterReturning(pointcut = "webTime()",returning = "rvt")
public void doAfterReturning(Object rvt){
log.info("-----------Start WebTimeAspect doAfterReturning ------");
log.info("本次处理请求耗费时间 : {}",(System.currentTimeMillis() - startTime.get()));
log.info("-----------End WebTimeAspect doAfterReturning -------------------------------");
}
}
在上述代码中每个aspect类的顶部都有一个注释@Order,这个注释是标记整个切面类的运行优先级的,我们的@Before与@AfterReturning根据order值执行的顺序是不一样的。 @Before order越小越优先 @AfterReturning order越大越优先
本文的相关例子可以查看仓库中的RapidDevelopment-demo3
目录:
Gitee 地址
88x31.png
知识共享许可协议 本作品由 cn華少 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。