springboot aop添加日志方式
一、首先自定義注解類SysLogAnnotation
/** * @date 2019/2/1 操作日志注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SysLogAnnotation { /** * 描述 * @return {String} */ String value(); }
二、添加切面類SysLogAspect,實(shí)現(xiàn)同一的日志添加
1、使用@Aspect注解定義切面類
@Component注冊(cè)bean
@Around(“@annotation(sysLogAnnotation)”)
實(shí)現(xiàn)切面環(huán)繞監(jiān)聽添加了@sysLogAnnotation注解的方法,
通過sysLogAnnotation.value()獲取注解中的value值
@Aspect @Slf4j @Component public class SysLogAspect { @Around("@annotation(sysLogAnnotation)") @SneakyThrows public Object around(ProceedingJoinPoint point, com.example.swaggerdemo.annotation.SysLogAnnotation sysLogAnnotation) { String strClassName = point.getTarget().getClass().getName(); String strMethodName = point.getSignature().getName(); log.debug("[類名]:{},[方法]:{}", strClassName, strMethodName); SysLog logVo = SysLogUtils.getSysLog(); logVo.setTitle(sysLogAnnotation.value()); // 發(fā)送異步日志事件 Long startTime = System.currentTimeMillis(); Object obj; try { obj = point.proceed(); } catch (Exception e) { logVo.setType(LogTypeEnum.ERROR.getType()); logVo.setException(e.getMessage()); throw e; } finally { Long endTime = System.currentTimeMillis(); logVo.setTime(String.valueOf(endTime - startTime)); SpringContextHolder.publishEvent(new SysLogEvent(logVo)); } return obj; } } @Slf4j @UtilityClass public class SysLogUtils { public SysLog getSysLog() { //獲取請(qǐng)求url,ip,httpMethod HttpServletRequest request = ((ServletRequestAttributes) Objects .requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); SysLog sysLog = new SysLog(); //sysLog.setCreateBy(Objects.requireNonNull(getUsername())); //sysLog.setUpdateBy(Objects.requireNonNull(getUsername())); sysLog.setType(LogTypeEnum.NORMAL.getType()); sysLog.setRemoteAddr(ServletUtil.getClientIP(request)); sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI())); sysLog.setMethod(request.getMethod()); sysLog.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT)); sysLog.setParams(HttpUtil.toParams(request.getParameterMap())); //sysLog.setServiceId(getClientId(request)); return sysLog; } }
2、通過繼承ApplicationEvent
自定義事件SysLogEvent
public class SysLogEvent extends ApplicationEvent { public SysLogEvent(SysLog source) { super(source); } }
3、通過實(shí)現(xiàn)ApplicationContextAware接口
獲得自定義上下文管理器
調(diào)用applicationContext.publishEvent(event)方法發(fā)布事件
在切面監(jiān)聽方法時(shí),調(diào)用事件發(fā)布方法發(fā)布事件
@Slf4j @Service @Lazy(false) public class SpringContextHolder implements ApplicationContextAware, DisposableBean { private static ApplicationContext applicationContext = null; /** * 取得存儲(chǔ)在靜態(tài)變量中的ApplicationContext. */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 實(shí)現(xiàn)ApplicationContextAware接口, 注入Context到靜態(tài)變量中. */ @Override public void setApplicationContext(ApplicationContext applicationContext) { SpringContextHolder.applicationContext = applicationContext; } /** * 從靜態(tài)變量applicationContext中取得Bean, 自動(dòng)轉(zhuǎn)型為所賦值對(duì)象的類型. */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { return (T) applicationContext.getBean(name); } /** * 從靜態(tài)變量applicationContext中取得Bean, 自動(dòng)轉(zhuǎn)型為所賦值對(duì)象的類型. */ public static <T> T getBean(Class<T> requiredType) { return applicationContext.getBean(requiredType); } /** * 清除SpringContextHolder中的ApplicationContext為Null. */ public static void clearHolder() { if (log.isDebugEnabled()) { log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext); } applicationContext = null; } /** * 發(fā)布事件 * @param event */ public static void publishEvent(ApplicationEvent event) { if (applicationContext == null) { return; } applicationContext.publishEvent(event); } /** * 實(shí)現(xiàn)DisposableBean接口, 在Context關(guān)閉時(shí)清理靜態(tài)變量. */ @Override @SneakyThrows public void destroy() { SpringContextHolder.clearHolder(); } }
三、編寫類監(jiān)聽事件
通過@EventListener(SysLogEvent.class)注解指定監(jiān)聽的時(shí)間
@Async注解異步執(zhí)行事件
@RequiredArgsConstructor注解寫在類上可以代替@AutoWired注解
需要注意的是在注入時(shí)需要用final定義,或者使用@notnull注解
@Slf4j @RequiredArgsConstructor @Component public class SysLogListener { private final SysLogMapper sysLogMapper; @Async @Order @EventListener(SysLogEvent.class) public void saveSysLog(SysLogEvent event) { SysLog sysLog = (SysLog) event.getSource(); sysLogMapper.insert(sysLog); } }
四、在controller中的方法上
加上@SysLogAnnotation注解就可以實(shí)現(xiàn)通過aop切面的方式來添加日志
@SysLogAnnotation("導(dǎo)出日志") @ApiOperation(value = "導(dǎo)出測試",notes = "導(dǎo)出測試") @GetMapping("export") public Object exportTest() { exportService.testExport(); return "success"; }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)DFA算法對(duì)敏感詞、廣告詞過濾功能示例
本篇文章主要介紹了Java實(shí)現(xiàn)DFA算法對(duì)敏感詞、廣告詞過濾功能示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11Swagger2匹配多個(gè)controller代碼實(shí)例
這篇文章主要介紹了Swagger2匹配多個(gè)controller代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09Java中import java.util.Scanner的用處詳解
文章主要介紹Java中的Scanner類及其常用方法next()和nextLine()的區(qū)別,next()方法在遇到空格、Tab鍵、回車鍵等分隔符時(shí)結(jié)束輸入,而nextLine()方法則接收所有輸入,直到遇到回車鍵2024-11-11