springboot通过自定义注解和AOP来实现业务日志记录的功能 您所在的位置:网站首页 loggerinfo日志没出来 springboot通过自定义注解和AOP来实现业务日志记录的功能

springboot通过自定义注解和AOP来实现业务日志记录的功能

2023-09-17 04:06| 来源: 网络整理| 查看: 265

外链:访问地址 1、首先是环境

我使用的是spring-boot构建的项目,通过自定义注解,aop来实现业务日志的记录

2、pom引入aop模块 org.springframework.boot spring-boot-starter-aop 3、创建自定义注解接口AccessLogger /** * 当产生访问日志时,将调用此方法.注意,此方法内的操作应尽量设置为异步操作,否则可能影响请求性能 * @param loggerInfo 产生的日志信息 */ void onLogger(AccessLoggerInfo loggerInfo); /** * 日志响应前执行的方法 * @param loggerInfo */ default void onLogBefore(AccessLoggerInfo loggerInfo){} } AccessLoggerListenerImpl代码 package com.wangfj.aoplogannotation.config.log.listener; import com.wangfj.aoplogannotation.config.log.object.AccessLoggerInfo; import org.springframework.stereotype.Component; /** * @author wangfujie * @date 2018-12-07 15:44 * @description 记录日志实现类 */ @Component public class AccessLoggerListenerImpl implements AccessLoggerListener { /** * 当产生访问日志时,将调用此方法.注意,此方法内的操作应尽量设置为异步操作,否则可能影响请求性能 * * @param loggerInfo 产生的日志信息 */ @Override public void onLogger(AccessLoggerInfo loggerInfo) { //此处写日志记录到数据库的代码 System.out.println("自定义日志注解成功!"); } } 6、创建注解解剖器接口AccessLoggerParser和它的实现类,主要用于获取注解的一些参数的 AccessLoggerParser代码 package com.wangfj.aoplogannotation.config.log.parser; import com.wangfj.aoplogannotation.config.log.aop.MethodInterceptorHolder; import com.wangfj.aoplogannotation.config.log.object.LoggerDefine; import java.lang.reflect.Method; /** * @author wangfujie * @date 2018-12-06 15:37 * @description 注解解剖器接口 */ public interface AccessLoggerParser { /** * 判断注解是否启用支持的方法 * @param clazz * @param method * @return */ boolean support(Class clazz, Method method); /** * 格式化注解参数处理 * @param holder * @return */ LoggerDefine parse(MethodInterceptorHolder holder); } DefaultAccessLoggerParser代码 package com.wangfj.aoplogannotation.config.log.parser; import com.wangfj.aoplogannotation.config.annotation.AccessLogger; import com.wangfj.aoplogannotation.config.log.aop.MethodInterceptorHolder; import com.wangfj.aoplogannotation.config.log.object.LoggerDefine; import org.springframework.core.annotation.AnnotationUtils; import java.lang.reflect.Method; import java.util.Objects; import java.util.stream.Stream; /** * @author wangfujie * @date 2018-12-06 15:38 * @description */ public class DefaultAccessLoggerParser implements AccessLoggerParser { @Override public boolean support(Class clazz, Method method) { AccessLogger ann = AnnotationUtils.findAnnotation(method, AccessLogger.class); //注解了并且未取消 return null != ann && !ann.ignore(); } @Override public LoggerDefine parse(MethodInterceptorHolder holder) { AccessLogger methodAnn = holder.findMethodAnnotation(AccessLogger.class); AccessLogger classAnn = holder.findClassAnnotation(AccessLogger.class); String action = Stream.of(classAnn, methodAnn) .filter(Objects::nonNull) .map(AccessLogger::module) .reduce((c, m) -> c.concat("-").concat(m)) .orElse(";"); String describe = Stream.of(classAnn, methodAnn) .filter(Objects::nonNull) .map(AccessLogger::describe) .flatMap(Stream::of) .reduce((c, s) -> c.concat("\n").concat(s)) .orElse(""); Integer type = null; if (null != methodAnn){ type = methodAnn.type().getValue(); } return new LoggerDefine(action,describe,type); } } 7、创建注解处理类MethodInterceptorHolder package com.wangfj.aoplogannotation.config.log.aop; import com.wangfj.aoplogannotation.utils.AopUtils; import com.wangfj.aoplogannotation.utils.ThreadLocalUtils; import org.aopalliance.intercept.MethodInvocation; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.util.DigestUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; /** * @author wangfujie * @date 2018-12-06 15:44 * @description DESCRIPTION */ public class MethodInterceptorHolder { /** * 参数名称获取器,用于获取方法参数的名称 */ public static final ParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); private String id; private Method method; private Object target; private Map args; public static MethodInterceptorHolder current() { return ThreadLocalUtils.get(MethodInterceptorHolder.class.getName()); } public static MethodInterceptorHolder clear() { return ThreadLocalUtils.getAndRemove(MethodInterceptorHolder.class.getName()); } public static MethodInterceptorHolder setCurrent(MethodInterceptorHolder holder) { return ThreadLocalUtils.put(MethodInterceptorHolder.class.getName(), holder); } public static MethodInterceptorHolder create(MethodInvocation invocation) { String id = DigestUtils.md5DigestAsHex(String.valueOf(invocation.getMethod().hashCode()).getBytes()); String[] argNames = nameDiscoverer.getParameterNames(invocation.getMethod()); Object[] args = invocation.getArguments(); Map argMap = new LinkedHashMap(); for (int i = 0, len = args.length; i MethodInterceptorHolder.setCurrent(this); return this; } public MethodInterceptorHolder(String id, Method method, Object target, Map args) { Objects.requireNonNull(id); Objects.requireNonNull(id); Objects.requireNonNull(method); Objects.requireNonNull(target); Objects.requireNonNull(args); this.id = id; this.method = method; this.target = target; this.args = args; } public String getId() { return id; } public Method getMethod() { return method; } public Object getTarget() { return target; } public Map getArgs() { return args; } public T findMethodAnnotation(Class annClass) { return AopUtils.findMethodAnnotation(annClass, method, annClass); } public T findClassAnnotation(Class annClass) { return AopUtils.findAnnotation(target.getClass(), annClass); } public T findAnnotation(Class annClass) { return AopUtils.findAnnotation(target.getClass(), method, annClass); } } 8、创建aop封装数据触发日志记录的支持类AopAccessLoggerSupport package com.wangfj.aoplogannotation.config.log.aop; import com.wangfj.aoplogannotation.config.annotation.AccessLogger; import com.wangfj.aoplogannotation.config.log.listener.AccessLoggerListener; import com.wangfj.aoplogannotation.config.log.object.AccessLoggerInfo; import com.wangfj.aoplogannotation.config.log.object.LoggerDefine; import com.wangfj.aoplogannotation.config.log.parser.AccessLoggerParser; import com.wangfj.aoplogannotation.utils.AopUtils; import com.wangfj.aoplogannotation.utils.WebUtil; import com.wangfj.aoplogannotation.utils.constant.SysLogType; import org.aopalliance.intercept.MethodInterceptor; import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; import org.springframework.core.Ordered; import org.springframework.util.ClassUtils; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * @author wangfujie * @date 2018-12-06 15:19 * @description 使用AOP记录访问日志,并触发{@link AccessLoggerListener#onLogger(AccessLoggerInfo)} */ public class AopAccessLoggerSupport extends StaticMethodMatcherPointcutAdvisor { private final List listeners = new ArrayList(); private final List loggerParsers = new ArrayList(); public AopAccessLoggerSupport addListener(AccessLoggerListener loggerListener) { listeners.add(loggerListener); return this; } public AopAccessLoggerSupport addParser(AccessLoggerParser parser) { loggerParsers.add(parser); return this; } public AopAccessLoggerSupport() { setAdvice((MethodInterceptor) methodInvocation -> { MethodInterceptorHolder methodInterceptorHolder = MethodInterceptorHolder.create(methodInvocation); AccessLoggerInfo info = createLogger(methodInterceptorHolder); Object response; try { listeners.forEach(listener -> listener.onLogBefore(info)); //响应前 response = methodInvocation.proceed(); //响应后 info.setResponse(response); info.setResponseTime(System.currentTimeMillis()); } catch (Throwable e) { info.setException(e); info.setAction("异常"); throw e; } finally { //触发监听(做业务处理) listeners.forEach(listener -> listener.onLogger(info)); } return response; }); } protected AccessLoggerInfo createLogger(MethodInterceptorHolder holder) { AccessLoggerInfo info = new AccessLoggerInfo(); info.setRequestTime(System.currentTimeMillis()); LoggerDefine define = loggerParsers.stream() .filter(parser -> parser.support(ClassUtils.getUserClass(holder.getTarget()), holder.getMethod())) .findAny() .map(parser -> parser.parse(holder)) .orElse(null); if (define != null) { info.setModule(define.getModule()); info.setDescribe(define.getDescribe()); Integer type = define.getType(); SysLogType sysLogType = SysLogType.getSysLogType(type); switch (sysLogType){ case LOGIN: info.setAction("登录"); info.setActionType(SysLogType.LOGIN.getValue()); break; case REQUEST: info.setAction("访问操作"); info.setActionType(SysLogType.REQUEST.getValue()); break; case ADD: info.setActionType(SysLogType.ADD.getValue()); info.setAction("添加操作"); break; case EDIT: info.setActionType(SysLogType.EDIT.getValue()); info.setAction("修改操作"); break; case DEL: info.setActionType(SysLogType.DEL.getValue()); info.setAction("删除操作"); break; case UPLOAD: info.setActionType(SysLogType.UPLOAD.getValue()); info.setAction("上传"); break; case DOWNLOAD: info.setActionType(SysLogType.DOWNLOAD.getValue()); info.setAction("下载"); break; case EXCEPTION: info.setActionType(SysLogType.EXCEPTION.getValue()); info.setAction("异常"); break; } } info.setParameters(holder.getArgs()); info.setTarget(holder.getTarget().getClass()); info.setMethod(holder.getMethod()); HttpServletRequest request = WebUtil.getHttpServletRequest(); if (null != request) { info.setHttpHeaders(WebUtil.getHeaders(request)); info.setIp(WebUtil.getIpAddr(request)); info.setHttpMethod(request.getMethod()); info.setUrl(request.getRequestURL().toString()); } return info; } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } @Override public boolean matches(Method method, Class aClass) { AccessLogger ann = AopUtils.findAnnotation(aClass, method, AccessLogger.class); if (null == ann) { return false; } if (ann != null ;; ann.ignore()) { return false; } return true; } } 9、创建aop配置,使注解拦截生效AopAccessLoggerSupportConfiguration package com.wangfj.aoplogannotation.config; import com.wangfj.aoplogannotation.config.log.aop.AopAccessLoggerSupport; import com.wangfj.aoplogannotation.config.log.listener.AccessLoggerListener; import com.wangfj.aoplogannotation.config.log.parser.AccessLoggerParser; import com.wangfj.aoplogannotation.config.log.parser.DefaultAccessLoggerParser; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author wangfujie * @date 2018-12-10 13:19 * @description AOP 访问日志记录自动配置 */ @ConditionalOnClass(AccessLoggerListener.class) @Configuration public class AopAccessLoggerSupportConfiguration { @Bean @ConditionalOnMissingBean(AopAccessLoggerSupport.class) public AopAccessLoggerSupport aopAccessLoggerSupport() { return new AopAccessLoggerSupport(); } @Bean @ConditionalOnMissingBean(AccessLoggerParser.class) public AccessLoggerParser defaultAccessLoggerParser() { return new DefaultAccessLoggerParser(); } @Bean @ConditionalOnMissingBean(ListenerProcessor.class) public ListenerProcessor listenerProcessor(AopAccessLoggerSupport aopAccessLoggerSupport) { return new ListenerProcessor(aopAccessLoggerSupport); } public static class ListenerProcessor implements BeanPostProcessor { private final AopAccessLoggerSupport aopAccessLoggerSupport; public ListenerProcessor(AopAccessLoggerSupport aopAccessLoggerSupport) { this.aopAccessLoggerSupport = aopAccessLoggerSupport; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof AccessLoggerListener) { aopAccessLoggerSupport.addListener(((AccessLoggerListener) bean)); } if (bean instanceof AccessLoggerParser) { aopAccessLoggerSupport.addParser(((AccessLoggerParser) bean)); } return bean; } } } 10、到此大公告成,最后在你需要记录日志的方法上加上注解即可 @RestController @RequestMapping("/log") public class TestAopLogController { @RequestMapping("/test") @AccessLogger(module = "记录模块" , describe = "记录的描述" , type = SysLogType.REQUEST) public String test(String param){ System.out.println("参数:" + param); return "测试记录日志,返回内容"; } } 调用接口测试一下就可以了

源代码地址:https://github.com/wangfujie/aop-log-annotation



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有