zoukankan      html  css  js  c++  java
  • 【工具】方法日志打印+任务切片

    @

    方法日志打印

    最近开发遇到的一个问题是关于日志打印。日志非常重要,通过查看日志,我们可以快速排查问题。
    我们项目的整个系统内网关处做了拦截,能够看到前端传过来的日志,但是内部服务间调用,服务间的入参与出参看不到;还有,一些重要的方法如果要看到入参和出参,只能一个个去写log方法。
    这种重复的工作非常适合使用切面来写一些小工具。下面是我写的小工具,下面方法几乎是搬运一位老哥写的博客,老哥的博客找不见了,sorry。

    定义注释类

    /**
     * @Description 打印参数
     * @Author lkb
     * @CreateDate: 2021/3/25
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface MethodLog {
    }
    

    AOP 打印输入输出参数

    /**
     * @Description
     * @Author lkb
     * @CreateDate: 2021/3/25
     */
    @Aspect
    @Component
    @Slf4j
    public class MethodLogAspect {
    
        @Pointcut("@annotation(com.....annotion.MethodLog)")
        public void pointCut(){}
    
        @Around(value = "pointCut()")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
            try{
                MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                Method method = signature.getMethod();
                MethodLog annotation = method.getAnnotation(MethodLog.class);
                if (Objects.isNull(annotation)){
                    try {
                        return joinPoint.proceed();
                    } catch (Throwable throwable) {
                        log.error("method proceed fail. e = {}", throwable.getMessage(), throwable);
                        throw throwable;
                    }
                }else{
                    String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
                    log.info("methodName: "+methodName);
                    Object[] args = joinPoint.getArgs();
                    log.info("param: " + JsonUtil.toJSON(args));
    
                    Instant start = Instant.now();
                    log.info("method start. methodName = {}", methodName);
                    Object result = null;
                    try {
                        // 这里的result记得return
                        result = joinPoint.proceed();
                    } catch (Throwable throwable) {
                        log.error("method proceed fail. e = {}", throwable.getMessage(), throwable);
                        throw throwable;
                    }
    
                    log.info("method end. methodName = {}, cost = {}", methodName, ChronoUnit.MILLIS.between(start, Instant.now()));
    
                    return result;
                }
            }catch (Exception e){
                log.error("MethodLogAspect around fail. e= {}", e.getMessage(), e);
                throw e;
            }
        }
    }
    

    任务切片

    遇到的第二个问题是,
    在一个调用中,需要多次调用外部系统的服务,本来应该使用MQ去解耦,但是因为多方面原因只能维持现状(我们服务多次调用外部系统的服务)。这样导致整个请求特别慢,上线多台设备的时候可能需要十几二十秒。
    与其他两个系统的交互互不影响,相互独立。因此,我想到使用任务切片的方式来加快执行速度。
    下面是我写的任务切片小工具。

    DTO

    /**
     * @Description
     * @Author lkb
     * @CreateDate: 2021/3/26
     */
    @Data
    public class AsynTaskDTO<T, R> {
    
        public T param;
    
        public Function<T, R> function;
    
        public R resultData;
    
        public Boolean result;
    
        public String key;
    
        public AsynTaskDTO(Function<T,R> function, T param){
            this.function = function;
            this.param = param;
            this.result = false;
            this.key = String.valueOf(param.hashCode());
        }
    
    }
    

    任务切片实现类

    /**
     * @Description
     * @Author lkb
     * @CreateDate: 2021/3/26
     */
    @Slf4j
    @Getter
    public class AsynTaskUtil {
    
        private static final ForkJoinPool ASYNC_IO_POOL = new ForkJoinPool((Runtime.getRuntime().availableProcessors() << 1) + 1);
    
        private List<AsynTaskDTO> taskDTOS;
    
        public AsynTaskUtil(List<AsynTaskDTO> taskDTOS){
            this.taskDTOS = taskDTOS;
        }
    
        public boolean doTask(){
            CompletableFuture[] futures = taskDTOS.stream().map(task -> CompletableFuture.runAsync(() -> {
                try{
                    task.setResultData(task.getFunction().apply(task.getParam()));
                    task.setResult(true);
                }catch (Exception e){
                    log.error("AsynTaskUtil doTask fail. e = {}" + e.getMessage(), e);
                    task.setResult(false);
                }
            }, ASYNC_IO_POOL)).toArray(CompletableFuture[]::new);
    
            CompletableFuture.allOf(futures).join();
    
            boolean f = taskDTOS.stream().anyMatch(t -> Objects.equals(false, t.getResult()));
            return !f;
        }
    }
    
    欢迎关注我的公众号 -- 大白和小倔
  • 相关阅读:
    H5+ 分享到微信、朋友圈代码示例
    H5+ 重写在线升级版本比较代码
    H5+ a页面打开b页面,b页面加载成功后关闭当前页面,闪屏的规避解决方案
    MUI
    MUI
    MUI
    MUI
    Vue实战之【企业开发常见问题】
    step1:准备歌词之《前端开发是个啥》
    element-ui级联选择器(Cascader)获取级联对象 (主要是想获取:label值)
  • 原文地址:https://www.cnblogs.com/catlkb/p/14614204.html
Copyright © 2011-2022 走看看