我是靠谱客的博主 清新爆米花,最近开发中收集的这篇文章主要介绍JAVA调用方法统一打印日志和try/catch 实现思路1.1. 创建一个接口(用来获取函数真实的调用路径和方法)1.2. 创建一个函数接口(继承SerializedLambdaFunction)2. 创建获取枚举属性的接口3. 创建异常信息枚举类 (实现EnumMessage接口)4. 编写FunctionUtils工具类5. 使用方式(以调用Service为例),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

需求: 

        避免编写重复的代码,如何把下面的两个需求抽取成公共逻辑;

        1. 调用其他方法时打印被调用方法的路径、入参、以及执行耗时情况;

        2. 调用方法遇到异常时,灵活控制是否要捕获异常或者抛出异常;

 实现思路

  • 使用函数式编程;

1.1. 创建一个接口(用来获取函数真实的调用路径和方法)

package com.xxx.utils.function;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;

/**
 * 
 */
public interface SerializedLambdaFunction extends Serializable {

    /**
     * 这个方法返回的SerializedLambda是重点
     * @return
     * @throws Exception
     */
    default SerializedLambda getSerializedLambda() throws Exception {
        //writeReplace改了好像会报异常
        Method write = this.getClass().getDeclaredMethod("writeReplace");
        write.setAccessible(true);
        return (SerializedLambda) write.invoke(this);
    }

    /**
     * 获取函数真实调用的实现类名
     * @return
     */
    default String getImplClass() {
        try {
            return getSerializedLambda().getImplClass();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取函数真实调用的实现方法名
     * @return
     */
    default String getImplMethodName() {
        try {
            return getSerializedLambda().getImplMethodName();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取函数真实调用的类名#方法名
     * @return
     */
    default String getClassAndMethodName() {
        try {
            return getImplClass() + "#" + getImplMethodName();
        } catch (Exception e) {
            return null;
        }
    }
}

1.2. 创建一个函数接口(继承SerializedLambdaFunction)

        下面是只接收一个参数并且有返回值的函数接口,如果要编写多个参数的函数接口只需要在<>泛型中和apply方法中添加泛型即可;

package com.xxx.utils.function;

/**
 * 接收一个参数并返回结果的函数
 * 函数方法是 {@link #apply(Object)}
 *
 * @param <T> 第一个参数
 * @param <R> 返回结果
 */
@FunctionalInterface
public interface MonoFunction<T, R> extends SerializedLambdaFunction {

    /**
     * 使用指定的参数调用该方法
     *
     * @param t 第一个参数
     * @return 返回结果
     */
    R apply(T t);
}

2. 创建获取枚举属性的接口

package com.xxx.constant;

/**
 * 获取枚举属性
 */
public interface EnumMessage {
    /**
     * 获取code
     * @return
     */
    int getCode();

    /**
     * 获取信息
     * @return
     */
    String getMessage();
}

3. 创建异常信息枚举类 (实现EnumMessage接口)

package com.xxx.exception;

import com.xxx.EnumMessage;

/**
 * 实现EnumMessage接口
 */
public enum ErrorCode implements EnumMessage {
    
    ;

    /**
     * 错误代码
     */
    private int code;

    /**
     * 错误信息
     */
    private String message;

    ErrorCode(int errCode, String errMessage) {
        this.code = errCode;
        this.message = errMessage;
    }

    @Override
    public int getCode() {
        return code;
    }

    @Override
    public String getMessage() {
        return message;
    }
}

4. 编写FunctionUtils工具类

4.1. 编写接收函数的方法

方法介绍

  • apply(MonoFunction<T, R> function, T param):执行方法并返回结果,不进行异常处理;
  • applyTry(MonoFunction<T, R> function, T param):执行方法并返回结果,如果遇到异常则捕获并返回null值;
  • applyTry(MonoFunction<T, R> function, T param, ErrorCode exceptionMessage):执行方法并返回结果,如果遇到异常则捕获异常并抛出新的异常。
/**
     * 接受一个函数和一个参数,并执行函数调用返回结果
     *
     * @param function 函数
     * @param param 第一个参数
     * @param <R> 返回结果
     * @return
     */
    public static <T, R> R apply(MonoFunction<T, R> function, T param) {
        StopWatch stopWatch = new StopWatch();
        try {
            stopWatch.start();
            R result = function.apply(param);
            stopWatch.stop();
            return result;
        } finally {
            logInfo(function, String.valueOf(stopWatch.getTotalTimeMillis()), param);
        }
    }

    /**
     * 接受一个函数和一个参数,并执行函数调用返回结果;
     * 调用过程中遇到异常则会捕获异常,并返回null值
     *
     * @param function 函数
     * @param param 第一个参数
     * @param <R> 返回结果
     * @return
     */
    public static <T, R> R applyTry(MonoFunction<T, R> function, T param) {
        R apply = null;
        try {
            apply = apply(function, param);
        } catch (Exception e) {
            logError(e);
        }
        return apply;
    }

    /**
     * 接受一个函数和一个参数,并执行函数调用返回结果;
     * 调用过程中遇到异常则会抛出exception异常
     *
     * @param function 函数
     * @param param 第一个参数
     * @param exceptionMessage 异常信息
     * @param <R> 返回结果
     * @return
     */
    public static <T, R> R applyTry(MonoFunction<T, R> function, T param, EnumMessage exceptionMessage) {
        try {
            R apply = apply(function, param);
            return apply;
        } catch (Exception e) {
            logError(e);
            throw exception(exceptionMessage);
        }
    }

 4.2. 编写打印日志的方法

/**
     * 日志工具
     */
    private static final Log logger = LogFactory.get();

    /**
     * 日志信息
     */
    private static final String INFO_MESSAGE = "【调用信息】:%s(%s),耗时:%s毫秒";

    /**
     * 打印请求的方法路径和参数名称
     *
     * @param function 函数
     * @param params 参数
     */
    public static void logInfo(SerializedLambdaFunction function, String totalTimeMillis, Object... params) {
        String paramStr = Arrays.stream(params).map(JSON::toJSONString).collect(Collectors.joining(","));
        logger.info(String.format(INFO_MESSAGE, function.getClassAndMethodName(), paramStr, totalTimeMillis));
    }

    /**
     * 打印请求的方法路径和参数名称
     *
     * @param function 函数
     * @param param 参数
     */
    public static void logInfo(SerializedLambdaFunction function, Object... param) {
        logInfo(function, "-", param);
    }

    /**
     * 打印error级别的异常信息
     *
     * @param exception 异常
     */
    public static void logError(Exception exception) {
        logger.error(exception.getMessage(), exception);
    }

    /**
     * 默认异常信息
     */
    private static EnumMessage DEFAULT_MESSAGE = new EnumMessage() {
        @Override
        public int getCode() {
            return 0;
        }

        @Override
        public String getMessage() {
            return "获取信息失败";
        }
    };

    /**
     * 创建异常信息
     * @param message
     */
    private static RuntimeException exception(EnumMessage message) {
        if (ObjectUtils.isEmpty(message)) {
            message = DEFAULT_MESSAGE;
        }
        return new RuntimeException(message.getMessage(), message.getCode());
    }

4.3. 完整工具类代码 

package com.xxx.utils;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.xxx.EnumMessage;
import com.xxx.utils.function.*;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.util.StopWatch;

import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 函数工具类
 */
public class FunctionUtils {

    /**
     * 日志工具
     */
    private static final Log logger = LogFactory.get();

    /**
     * 日志信息
     */
    private static final String INFO_MESSAGE = "【调用信息】:%s(%s),耗时:%s毫秒";

    /**
     * 打印请求的方法路径和参数名称
     *
     * @param function 函数
     * @param params 参数
     */
    public static void logInfo(SerializedLambdaFunction function, String totalTimeMillis, Object... params) {
        String paramStr = Arrays.stream(params).map(JSON::toJSONString).collect(Collectors.joining(","));
        logger.info(String.format(INFO_MESSAGE, function.getClassAndMethodName(), paramStr, totalTimeMillis));
    }

    /**
     * 打印请求的方法路径和参数名称
     *
     * @param function 函数
     * @param param 参数
     */
    public static void logInfo(SerializedLambdaFunction function, Object... param) {
        logInfo(function, "-", param);
    }

    /**
     * 打印error级别的异常信息
     *
     * @param exception 异常
     */
    public static void logError(Exception exception) {
        logger.error(exception.getMessage(), exception);
    }

    /**
     * 默认异常信息
     */
    private static EnumMessage DEFAULT_MESSAGE = new EnumMessage() {
        @Override
        public int getCode() {
            return 0;
        }

        @Override
        public String getMessage() {
            return "获取信息失败";
        }
    };

    /**
     * 创建异常信息
     * @param message
     */
    private static xxxException exception(EnumMessage message) {
        if (ObjectUtils.isEmpty(message)) {
            message = DEFAULT_MESSAGE;
        }
        // 自定义一个Exception,接收一个message和一个code
        return new xxxException(message.getMessage(), message.getCode());
    }

    /**
     * 接受一个函数和一个参数,并执行函数调用返回结果
     *
     * @param function 函数
     * @param param 第一个参数
     * @param <R> 返回结果
     * @return
     */
    public static <T, R> R apply(MonoFunction<T, R> function, T param) {
        StopWatch stopWatch = new StopWatch();
        try {
            stopWatch.start();
            R result = function.apply(param);
            stopWatch.stop();
            return result;
        } finally {
            logInfo(function, String.valueOf(stopWatch.getTotalTimeMillis()), param);
        }
    }

    /**
     * 接受一个函数和一个参数,并执行函数调用返回结果;
     * 调用过程中遇到异常则会捕获异常,并返回null值
     *
     * @param function 函数
     * @param param 第一个参数
     * @param <R> 返回结果
     * @return
     */
    public static <T, R> R applyTry(MonoFunction<T, R> function, T param) {
        R apply = null;
        try {
            apply = apply(function, param);
        } catch (Exception e) {
            logError(e);
        }
        return apply;
    }

    /**
     * 接受一个函数和一个参数,并执行函数调用返回结果;
     * 调用过程中遇到异常则会抛出exception异常
     *
     * @param function 函数
     * @param param 第一个参数
     * @param exceptionMessage 异常信息
     * @param <R> 返回结果
     * @return
     */
    public static <T, R> R applyTry(MonoFunction<T, R> function, T param, EnumMessage exceptionMessage) {
        try {
            R apply = apply(function, param);
            return apply;
        } catch (Exception e) {
            logError(e);
            throw exception(exceptionMessage);
        }
    }
}

5. 使用方式(以调用Service为例)

5.1. 引入Service

@Autowired
private xxxService service;

5.2. 通过FunctionUtils调用service的方法

String id= "123456";
String value= FunctionUtils.applyTry(xxxService::getxxxById, id);

最后

以上就是清新爆米花为你收集整理的JAVA调用方法统一打印日志和try/catch 实现思路1.1. 创建一个接口(用来获取函数真实的调用路径和方法)1.2. 创建一个函数接口(继承SerializedLambdaFunction)2. 创建获取枚举属性的接口3. 创建异常信息枚举类 (实现EnumMessage接口)4. 编写FunctionUtils工具类5. 使用方式(以调用Service为例)的全部内容,希望文章能够帮你解决JAVA调用方法统一打印日志和try/catch 实现思路1.1. 创建一个接口(用来获取函数真实的调用路径和方法)1.2. 创建一个函数接口(继承SerializedLambdaFunction)2. 创建获取枚举属性的接口3. 创建异常信息枚举类 (实现EnumMessage接口)4. 编写FunctionUtils工具类5. 使用方式(以调用Service为例)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部