其目的是添加了@SysLog的注解【该注解通过自定义实现】的全部方法,以切面的方式,收集调用时的相关信息【如用户名称,调用接口名称,ip地址等信息】执行切面方法 ,将此信息存入到数据库中。
切面方法是通过发布一个SpringEvent监听事件实现,当Listener监听到此事件的发生时,异步执行数据库操作。将信息存入到数据库中。后续开发人员可根据logger日志信息分析并处理相关的异常
步骤1 定义日志操作事件类SysLogEvent
/**
* @author lyf
* @projectName demo
* @date 2022/2/16 下午 08:00
* @description 封装日志收集到的相关信息【可以根据实际情形自定义封装需要自定义的相关信息】
*/
@Data
public class SysLogEntity {
private String userEmp;
private String descprtion;
private String ip;
private String url;
private String method;
}
/**
* @author lyf
* @projectName demo
* @date 2022/2/16 下午 08:03
* @description 日志事件
*/
public class SysLogEvent extends ApplicationEvent {
public SysLogEvent(SysLogEntity entity) {
super(entity);
}
}
步骤2、定义@SysLog注解【涉及到SpringEvent的发布】
该注解用于在Controller的方法上标注,标识当前方法需要进行操作日志的保存处理
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SysLog {
/**
* 方法描述
*
* @return
*/
String descprtion() default "";
}
步骤3、定义SpringEvent——SysLogEvent
public class SysLogEvent extends ApplicationEvent {
public SysLogEvent(SysLogEntity entity) {
super(entity);
}
}
步骤4、定义切面类SysLogAspect,通知方法中发布事件SysLogEvent
@Aspect
@Component
public class SysLogAspect {
private Logger logger= LoggerFactory.getLogger(SysLogAspect.class);
@Autowired
HttpServletRequest request;
@Autowired
private ApplicationEventPublisher publisher;
/**
* 定义切点,当标注了@SysLog的注解之后将会执行AOP增强切面操作,执行定义的通知,存储Log信息
*/
@Pointcut("@annotation(com.anotation.SysLog)")
public void logPointCut() {}
/**
* 环绕通知
*/
@Around(value = "logPointCut()")
public void aroundAdvice(ProceedingJoinPoint point){
try {
//日志对象
SysLogEntity entity=new SysLogEntity();
logger.info("执行前");
//前置通知
MethodSignature signature = (MethodSignature)point.getSignature();
entity.setMethod(signature.getName());
SysLog annotation = signature.getMethod().getAnnotation(SysLog.class);
if(annotation!=null){
//通过反射,获得当前注解中的相关信息
entity.setDescription(annotation.descprtion());
}
long startTime= System.currentTimeMillis();
point.proceed();
long endTime= System.currentTimeMillis();
entity.setMs(endTime-startTime);
entity.setIp(request.getRemoteAddr());
entity.setUrl(request.getRequestURI());
entity.setController(point.getTarget().toString());
//发送LogEvent;
ApplicationEvent event=new SysLogEvent(entity);
publisher.publishEvent(event);
} catch (Throwable throwable) {
//異常通知
throwable.printStackTrace();
}
}
}
步骤6、 定义事件监听器
@Component
public class LogListener {
/**
* 监听SyslogEvent事件的发生
*/
@EventListener(SysLogEvent.class)
public void saveLogListener(SysLogEvent event){
SysLogEntity source = (SysLogEntity)event.getSource();
//打印信息模拟数据库操作
System.out.println("event save data ");
System.out.println(source.toString());
}
}
步骤7、 测试类
@RestController
@RequestMapping("/user")
public class UserController {
Logger logger = LoggerFactory.getLogger(UserController.class);
@SysLog(descprtion = "获得用户信息")
@GetMapping("/get")
public String getUser(String emp){
//TRACE<DEBUG 忽略
logger.trace("trace...");
logger.debug("debug...");
logger.info("info...");
logger.warn("warn...");
logger.error("error...");
return "OK";
}
}
项目结构图如下,当启动测试类后,浏览器请求http://localhost:8080/user/get后,标注了@SysLog的注解将进入增强切面,获得请求调用时的相关信息,log信息会打印在控制台上,自定义注解记录log功能正常!