在 Spring Boot 中来实现 AOP 切面实现日志统一输出
AOP
全称:Aspect Oriented Programming。是一种面向切面编程的,利用预编译方式和运行期动态代理实现程序功能统一的一种技术。它也是Spring
很重要的一部分,和IOC
一样重要。利用AOP
可以很好的对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
本文主要利用注解解决系统日志统一输出问题
话不多说,直接上代码:
工程pom.xml
log日志注解类:
package com.mscloudmesh.aop.springbootaoplogs.annoation;
import java.lang.annotation.*;
/**
* @author kevin
* @date 2020/6/9
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Log {
String value() default "";
}
日志切面类实现:
package com.mscloudmesh.aop.springbootaoplogs.aspect;
import com.mscloudmesh.aop.springbootaoplogs.annoation.Log;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
@Aspect
@Component
@Slf4j
public class LogAspect {
//设置切入点:这里直接拦截被@RestController注解的类
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
public void pointcut() {
}
/**
* 切面方法,记录日志
*
* @return
*/
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long beginTime = System.currentTimeMillis();//1、开始时间
//利用RequestContextHolder获取requst对象
ServletRequestAttributes requestAttr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
String uri = requestAttr.getRequest().getRequestURI();
log.info("方法请求开始: {} URI: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), uri);
//访问目标方法的参数 可动态改变参数值
Object[] args = joinPoint.getArgs();
//方法名获取
String methodName = joinPoint.getSignature().getName();
log.info("请求方法:{}, 请求参数: {}", methodName, Arrays.toString(args));
Signature signature = joinPoint.getSignature();
if (!(signature instanceof MethodSignature)) {
throw new IllegalArgumentException("非法注解");
}
//调用实际方法
Object object = joinPoint.proceed();
//获取执行的方法
MethodSignature methodSign = (MethodSignature) signature;
Method method = methodSign.getMethod();
Log log_desc = AnnotationUtils.getAnnotation(method, Log.class);
log.info("log描述:{}", log_desc.value());
long endTime = System.currentTimeMillis();
log.info("方法请求结束: {}, URI: {},耗时:{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), uri, endTime - beginTime);
return object;
}
}
Controller测试类:
package com.mscloudmesh.aop.springbootaoplogs.controller;
import com.mscloudmesh.aop.springbootaoplogs.annoation.Log;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("/log")
@Log(value = "请求了测试方法")
public String test(@RequestParam("param") String param) {
return param+":aop日志测试";
}
}
springboot主程序类:
package com.mscloudmesh.aop.springbootaoplogs;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootAopLogsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootAopLogsApplication.class, args);
}
}
application.yml配置文件:
server:
port: 8080
spring:
application:
name: aop-logs
请求http://localhost:8080/log?param=kevin
输出日志:
2020-06-09 23:04:49.793 INFO 10057 --- [nio-8080-exec-1] c.m.a.s.aspect.LogAspect : 方法请求开始: 2020-06-09 23:04:49 URI: /log
2020-06-09 23:04:49.794 INFO 10057 --- [nio-8080-exec-1] c.m.a.s.aspect.LogAspect : 请求方法:test, 请求参数: [kevin]
2020-06-09 23:04:49.803 INFO 10057 --- [nio-8080-exec-1] c.m.a.s.aspect.LogAspect : log描述:请求了测试方法
2020-06-09 23:04:49.803 INFO 10057 --- [nio-8080-exec-1] c.m.a.s.aspect.LogAspect : 方法请求结束: 2020-06-09 23:04:49, URI: /log,耗时:10