记录aop+多线程操作日志

上篇博文可以通过注解 标注在方法上实现aop,来对某个方法进行加强
呢么  我们该怎么通过aop 来实现日志的记录呢
大致是这样的思路
aop--->记录请求响应信息---> 利用线程池进行insert 操作保存日志信息

 @Before("dataProcess()") // 之前操作
 @AfterReturning(returning = "ret", pointcut = "dataProcess()") // 之后操作
 @AfterThrowing(value = "dataProcess()", throwing = "throwable") // 异常信息
 @After("dataProcess()")  首先我们得知道基于切点者4个的顺序
 没有异常的时候:Before--->切点-->after--->AfterReturning
 有异常的时候:Before--->切点-->after--->AfterThrowing

@Data
public class LogBean {
    /**
     * 浏览器信息
     */
    private String browserInfo;
    /**
     * 请求URL
     */
    private String requestURL;
    /**
     *  请求类型(get、post、put、delete等)
     */
    private String httpMethod;
    /**
     * 客户端请求IP
     */
    private String requestIP;
    /**
     * 请求参数
     */
    private String requestParam;

    /**
     * 操作的类和方法
     */
    private String operateClassMethod;
    /**
     * 耗时
     */
    private long consumeTime;
    /***
     * 响应结果
     */
    private String responseResult;
    /**
     * 操作描述
     */
    private String operateDesc;
    /**
     * 异常信息
     */
    private String exceptionMsg;
    /**
     * 操作时间
     */
    private String operateTime;


}
// 我们封装一个javabean 可以重写他的tostring 方式 让他的tosting 编程日志格式  类似于下面的

在这里插入图片描述

 然后我们在声明一个 注解  默认是持久化的 第一个参数就是你的比如说 保存用户
 @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebLog {
    //  操作描述
    String value() default "";
    // true 表示持久化日志,false表示不持久化
    boolean persistent() default true;
}

spring的aop 记录 请求响应信息

@Aspect
@Component

public class WebLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
    private ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();
    private ThreadLocal<LogBean> webLogBeanThreadLocal = new ThreadLocal<>();
    private ThreadLocal<Boolean> isPersistentThreadLocal = new ThreadLocal<>();
      /**
     * 日志处理类
     */
    @Autowired
    private WebLogHandler webLogHandler;

    @Pointcut(value = "@annotation(com.util.annotation.WebLog)")
    public void dataProcess() {
    }

    @Before("dataProcess()") // 之前操作
    public void doBefore(JoinPoint joinPoint) throws Exception {
        logger.info("-------------我处理之前-------------");
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        LogBean logBean = new LogBean();
        logBean.setBrowserInfo(request.getHeader("User-Agent"));
        logBean.setRequestURL(request.getRequestURL().toString());
        String reqmethod = request.getMethod();
        logBean.setHttpMethod(reqmethod);
        logBean.setRequestIP(request.getRemoteAddr());
        // get请求
        // 存放请求数据

        /*get请求存储数据*/
        if ("GET DELETE".contains(reqmethod)) {
            HashMap<Object, Object> map = new HashMap<>();
            Map<String, String[]> parameterMap = request.getParameterMap();

            if (!ObjectUtils.isEmpty(parameterMap)) {
                // 获取请求数据
                for (String key : parameterMap.keySet()) {
                    String[] parmValue = parameterMap.get(key);
                    String finalValue = !ObjectUtils.isEmpty(parmValue) ? Arrays.stream(parmValue).collect(Collectors.joining(",")) : "";
                    map.put(key, finalValue);

                }

            }

            logBean.setRequestParam(map.toString());
        } else {
            /*Post请求存储数据*/
            InputStream in = request.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuffer sb = new StringBuffer();
            String str = "";
            while ((str = reader.readLine()) != null) {
                sb.append(str);
            }

            logBean.setRequestParam(sb.toString());

        }
        logBean.setOperateClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 当前方法名
        Method method = methodSignature.getMethod();
        WebLog webLog = method.getAnnotation(WebLog.class);
        /*反射获取此时这个方法的描述*/
        logBean.setOperateDesc(webLog.value());
        if (logger.isInfoEnabled()) {
            logger.info("请求参数:[" + logBean.toString() + "]");
        }
        startTimeThreadLocal.set(System.currentTimeMillis());// 记录时间  消耗时间
        isPersistentThreadLocal.set(webLog.persistent()); // 记录是否持久化
        webLogBeanThreadLocal.set(logBean);// 记录这个bean

    }

    @AfterReturning(returning = "ret", pointcut = "dataProcess()") // 之后操作
    public void doAfterReturning(Object ret) throws Throwable {
        if (webLogBeanThreadLocal.get() != null) {
            LogBean logBean = webLogBeanThreadLocal.get();
            if (startTimeThreadLocal.get() != null) {
                long startTime = startTimeThreadLocal.get();
                /*记录时间*/
                logBean.setConsumeTime(System.currentTimeMillis() - startTime);
            }
            if (ObjectUtils.isEmpty(ret)) {
                ret = "";
            }
            logBean.setResponseResult(ret.toString());
            String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            logBean.setOperateTime(nowTime);
            if (logger.isInfoEnabled()) {
//                logger.info("请求处理结束,参数:["+JSON.toJSONString(logBean)+"]");
            }
            Boolean persistentFlag = null;
            if (isPersistentThreadLocal.get() != null) {
                persistentFlag = isPersistentThreadLocal.get();
            }
            webLogHandler.processLog(logBean, persistentFlag);
        }
        startTimeThreadLocal.remove();
        webLogBeanThreadLocal.remove();
        isPersistentThreadLocal.remove();

    }


    @After("dataProcess()")
    public void after(JoinPoint jp) throws IOException {
        logger.info("-------------我处理完毕了-------------");

    }
    //后置异常通知

    @AfterThrowing(value = "dataProcess()", throwing = "throwable") // 异常信息
    public void throwException(JoinPoint jp, Throwable throwable) {
        logger.error("业务处理发生异常",throwable);

        if (webLogBeanThreadLocal.get() != null) {
            LogBean logBean = webLogBeanThreadLocal.get();
            if (startTimeThreadLocal.get()!=null) {
                long startTime = startTimeThreadLocal.get();
                logBean.setConsumeTime(System.currentTimeMillis() - startTime);
            }
            logBean.setExceptionMsg(throwable.getMessage());
            String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

            logBean.setOperateTime(nowTime);

            boolean persistentFlag=false;
            if (isPersistentThreadLocal.get()!= null) {
                persistentFlag=isPersistentThreadLocal.get();
            }
            webLogHandler.processLog(logBean, persistentFlag);
        }
        startTimeThreadLocal.remove();
        webLogBeanThreadLocal.remove();
        isPersistentThreadLocal.remove();

    }

}

 webLogHandler.processLog(logBean, persistentFlag);
 核心就在于这里 记录下来的日志信息我们需要利用异步 就得利用多线程来进行操作

public interface WebLogHandler<T> {
    /**
     * 处理日志
     * @param t 日志对象
     * @param isPersistent 是否需要持久化 true表示需要持久化、false表示不需要
     * @throws LogPersistenceException
     */
    void processLog(T t,boolean isPersistent) throws RuntimeException;

    /**
     * 持久化日志
     * @param t 持久化日志对象到数据库
     * @throws LogPersistenceException
     */
    void persistenceLog(T t) throws RuntimeException;


@Service
public class DefaultWebLogHandler implements WebLogHandler<LogBean> {

    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor; // 线程池

    @Autowired
    OperationLogService operationLogService;// 日志操作类 这个类用来做日志的insert操作

    @Override
    public void processLog(LogBean logBean, boolean isPersistent) throws RuntimeException {
        if (isPersistent) {
            this.persistenceLog(logBean);
        }
    }

    @Override
    public void persistenceLog(LogBean logBean) throws RuntimeException {
        this.threadPoolTaskExecutor.execute(
                new OperationLogThread(operationLogService,logBean));
    }


线程池 config 配置  可以利用@value读取文件
@Configuration

public class LogConfiguration {

    private int corePoolSize=5;

    private int maxPoolSize=10;
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor=new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
        threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
        threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        return threadPoolTaskExecutor;
    }

}

  线程池 操作线程  对日志进行insert
public class OperationLogThread implements Runnable {
    private OperationLogService operationLogService;
    private LogBean logBean;
    public OperationLogThread(OperationLogService operationLogService, LogBean logBean) {
        this.operationLogService=operationLogService;
        this.logBean=logBean;
    }

    @Override
    public void run() {
        operationLogService.insertLog( logBean);
    }
}

public interface OperationLogService {
    void insertLog(LogBean logBean);
}

此时应该连接db 做insert 操作  我此时也就吧日志打印出来了
@Service
public class OperationLogServiceImpl  implements OperationLogService {
    @Override
    public void insertLog(LogBean logBean) {
        System.out.println(logBean.toString());
    }
}

在这里插入图片描述

最后可以把这个commonLog打成jar 
  <dependency>
            <artifactId>commonLog</artifactId>
            <groupId>org.example</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
  @GetMapping
    @WebLog(value="用户新增")
    public String getResult() {
        System.out.println("访问了");
       
        return "abc";
    }
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值