java:反射封装Slf4j日志工具类
1 前言
使用Slf4j时,针对日志打印进行工具类封装使用。
依赖如下:
<parent>
<groupId>org.springframework.boot</groupId>
<version>2.5.4</version>
<artifactId>spring-boot-starter-parent</artifactId>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- slf4j 日志门面 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<!-- logback日志实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- spring-boot 3.12.0 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
2 使用
Slf4j日志工具类,反射封装:
LogUtils:
package com.xiaoxu.crawler.utils;
import com.xiaoxu.crawler.base.constant.PlaceholderConstant;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Date;
/**
* @author xiaoxu
* @date 2022-11-21 10:52
* crawlerJ:com.xiaoxu.crawler.utils.LogUtil
*/
public class LogUtils implements PlaceholderConstant {
/* log日志时间pattern */
private static final String logPattern = "yyyy-MM-dd HH:mm:ss.SSS";
/* 日志方法stack层级 */
private static final int logStackHierarchy = 6;
public static <R> void logDetailInfo(Logger logger, String methodName, R requestPayload,
long timeConsuming){
String msg = logDetailCheck(methodName, timeConsuming);
info(logger, msg, methodName, requestPayload, timeConsuming);
}
public static <R> void logDetailWarn(Logger logger, String methodName, R requestPayload,
long timeConsuming){
String msg = logDetailCheck(methodName, timeConsuming);
warn(logger, msg, methodName, requestPayload, timeConsuming);
}
public static <R> void logDetailError(Logger logger, String methodName, R requestPayload,
long timeConsuming){
String msg = logDetailCheck(methodName, timeConsuming);
error(logger, msg, methodName, requestPayload, timeConsuming);
}
private static String logDetailCheck(String methodName, long timeConsuming) {
AssertUtils.assertTrue(timeConsuming >= 0, "日志耗时参数有误, 请检查");
AssertUtils.assertNonEmpty(methodName, "日志请求方法参数有误, 请检查");
return "调用"+squarePrefix+"{}"+squareSuffix+"方法, 请求参数:"+squarePrefix+"{}"+squareSuffix+", 耗时:"+squarePrefix+"{}"+squareSuffix+"ms.";
}
public static void info(Logger logger, String formatMsg, Object... objects){
commLogExecute(logger, formatMsg, objects);
}
public static void warn(Logger logger, String formatMsg, Object... objects){
commLogExecute(logger, formatMsg, objects);
}
public static void error(Logger logger, String formatMsg, Object... objects){
commLogExecute(logger, formatMsg, objects);
}
private static void commLogExecute(Logger logger, String formatMsg, Object[] objects) {
logCheck(logger, formatMsg, objects);
ReflectExecuteLog(logger, formatMsg, objects);
}
private static void ReflectExecuteLog(Logger logger, String formatMsg, Object[] objects) {
IfElseUtils.executeBothSide(ArrayUtils.isNotEmpty(objects), new IfElseUtils.ActionCallBack() {
@Override
public void actionTrue() {
/* logger.info(buildWrapMessage(formatMsg), objects); */
Method logMethodByName = getReflectLogMethod("执行actionTrue失败,日志方法未匹配到!{0}");
try {
if(null != logMethodByName){
logMethodByName.invoke(logger, buildWrapMessage(formatMsg, logMethodByName.getName()), objects);
}
} catch (IllegalAccessException | InvocationTargetException e) {
ExcpUtils.throwExp(MessageFormat.format("反射执行logger方法失败!{0}",e.getMessage()));
}
}
@Override
public void actionFalse() {
/* logger.info(buildWrapMessage(formatMsg)); */
Method logMethodByName = getReflectLogMethod("执行actionFalse失败,日志方法未匹配到!{0}");
try {
if(null != logMethodByName){
logMethodByName.invoke(logger,buildWrapMessage(formatMsg, logMethodByName.getName()), null);
}
} catch (IllegalAccessException | InvocationTargetException e) {
ExcpUtils.throwExp(MessageFormat.format("反射执行logger方法失败!{0}",e.getMessage()));
}
}
private Method getReflectLogMethod(String msg) {
Method logMethodByName = LogMethods.getLogMethodByName(Thread.currentThread().getStackTrace()[logStackHierarchy].getMethodName());
AssertUtils.assertNonNull(logMethodByName, MessageFormat
.format(msg,
Thread.currentThread().getStackTrace()[logStackHierarchy].getMethodName()));
return logMethodByName;
}
});
}
/* 日志方法映射枚举 */
enum LogMethods implements LogConstant{
/* 日志方法枚举映射 */
INFO(LogConstant.INFO,
handleEnumerationExp(LogConstant.INFO)),
WARN(LogConstant.WARN,
handleEnumerationExp(LogConstant.WARN)),
ERROR(LogConstant.ERROR,
handleEnumerationExp(LogConstant.ERROR));
private String logMethodName;
private Method logMethod;
LogMethods(String logMethodName, Method logMethod){
this.logMethodName = logMethodName;
this.logMethod = logMethod;
AssertUtils.assertTrue(null != logMethodName && logMethodName.equals(logMethod.getName()), "初始化日志名与日志方法失败!!不匹配.");
}
private static Method handleEnumerationExp(String logMethodName){
Method method = null;
try {
method = Logger.class.getMethod(logMethodName, String.class, Object[].class);
} catch (NoSuchMethodException e) {
ExcpUtils.throwExp(MessageFormat.format("NoSuchMethod:日志枚举方法初始化异常!!!{0},日志枚举方法名称:{1}.",
e.getMessage(), logMethodName));
} catch (Throwable tx){
ExcpUtils.throwExp(MessageFormat.format("Throwable:日志枚举方法初始化未知异常!!!{0},日志枚举方法名称:{1}.",
tx.getMessage(), logMethodName));
}
return method;
}
public String getLogMethodName() {
return logMethodName;
}
public void setLogMethodName(String logMethodName) {
this.logMethodName = logMethodName;
}
public Method getLogMethod() {
return logMethod;
}
public void setLogMethod(Method logMethod) {
this.logMethod = logMethod;
}
public static Method getLogMethodByName(String logMethodName){
if(!StringUtils.hasLength(logMethodName)){
ExcpUtils.throwExp("请求日志枚举方法getLogMethodByName的logMethodName不能为空");
}
for (LogMethods value : LogMethods.values()) {
if(value.getLogMethodName().equals(logMethodName)){
return value.getLogMethod();
}
}
return null;
}
}
interface LogConstant{
/* 日志级别 */
String INFO = "info";
String WARN = "warn";
String ERROR = "error";
}
@SuppressWarnings(value = "all")
private static String buildWrapMessage(final String msg, final String methodName){
/* 日志打印补充公共信息 */
StringBuffer sb = new StringBuffer();
final String concat = " " + horizontalLineConcat + " ";
sb.append(squarePrefix);
sb.append(DateUtils.formatDate(new Date(), logPattern));
sb.append(concat).append(methodName);
sb.append(squareSuffix).append(" ");
sb.append(msg);
return sb.toString();
}
private static void logCheck(Logger logger, String formatMsg, Object... objects){
AssertUtils.assertNonNull(logger, "log should not be null");
AssertUtils.assertNonEmpty(formatMsg, "log's format message should not be null or empty");
if(matchCount(formatMsg, placeholderPrefix, formatMsg, placeholderSuffix)){
if(StrUtils.getMatchCount(formatMsg, placeholderPrefix) > 0){
/* slf4j占位符打印日志 */
AssertUtils.assertTrue(
countAndObjLenMatch(StrUtils.getMatchCount(formatMsg, placeholderPrefix), objects),"log's objects should match placeholders.");
}else{
AssertUtils.assertTrue(ArrayUtils.isEmpty(objects), "when no placeholders, objects should be null or empty array.");
}
}else{
ExcpUtils.throwExp("please check placeholder's left should match right.");
}
}
private static boolean countAndObjLenMatch(int counts, Object... objects){
AssertUtils.assertTrue(counts > 0, "countAndObjLenMatch's counts may be wrong.");
return ArrayUtils.isNotEmpty(objects) && objects.length == counts;
}
private static boolean matchCount(final String str1, final String subStr1, final String str2, final String subStr2){
AssertUtils.assertNonEmpty(str1, "matchCount's str1 should not be null or empty.");
AssertUtils.assertNonEmpty(str1, "matchCount's subStr1 should not be null or empty.");
AssertUtils.assertNonEmpty(str1, "matchCount's str2 should not be null or empty.");
AssertUtils.assertNonEmpty(str1, "matchCount's subStr2 should not be null or empty.");
return StrUtils.getMatchCount(str1, subStr1) == StrUtils.getMatchCount(str2, subStr2);
}
public static void main(String[] args) {
// info(LoggerFactory.getLogger(LogUtils.class),"今天星期是","1","2");
// info(LoggerFactory.getLogger(LogUtils.class),"今天星期是{}","1","2");
// info(LoggerFactory.getLogger(LogUtils.class),"今天星期是{}{","1","2");
info(LoggerFactory.getLogger(LogUtils.class),"今天星期是{}{}","1","2");
info(LoggerFactory.getLogger(LogUtils.class),"今天星期是", new Array[]{});
warn(LoggerFactory.getLogger(LogUtils.class),"空指针异常!{}", "please check");
error(LoggerFactory.getLogger(LogUtils.class),"严重错误!!!{},{}", "参数:","123");
logDetailInfo(LoggerFactory.getLogger(LogUtils.class), "getYou", 123,2121);
logDetailWarn(LoggerFactory.getLogger(LogUtils.class), "getYou", 123,2121);
logDetailError(LoggerFactory.getLogger(LogUtils.class), "getYou", 123,2121);
info(LoggerFactory.getLogger(LogUtils.class), "成功!!");
}
}
PlaceholderConstant:
package com.xiaoxu.crawler.base.constant;
/**
* @author xiaoxu
* @date 2022-11-21 12:04
* crawlerJ:com.xiaoxu.crawler.base.constant.PlaceholderConstant
*/
public interface PlaceholderConstant {
String placeholderPrefix = "{";
String placeholderSuffix = "}";
String squarePrefix = "[";
String squareSuffix = "]";
String horizontalLineConcat = "-";
}
DateUtils:
package com.xiaoxu.crawler.utils;
import org.springframework.util.StringUtils;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
/**
* @author xiaoxu
* @date 2022-11-22 0:00
* crawlerJ:com.xiaoxu.crawler.utils.DateUtils
*/
public class DateUtils {
private static final Object lockObj = new Object();
private static volatile Map<String, ThreadLocal<SimpleDateFormat>> timeLocalMaps = new HashMap<>();
public static String formatDate(Date date, String pattern){
AssertUtils.assertNonNull(date, "日期不能为null");
String format = null;
try {
format = getSDF(pattern).format(date);
} catch (IllegalArgumentException ie) {
ExcpUtils.throwExp(MessageFormat.format("日期格式化出现无效参数异常!{0}",
ie.getMessage()));
} catch (Throwable th) {
ExcpUtils.throwExp(MessageFormat.format("日期格式化出现未知异常!{0}",
th.getMessage()));
}
return format;
}
public static Date getDateByStr(String dateStr, String pattern){
AssertUtils.assertNonEmpty(dateStr, "dateStr should not be null or empty.");
AssertUtils.assertNonEmpty(pattern, "pattern should not be null or empty.");
AssertUtils.assertTrue(judgeStrLength(dateStr, pattern), "日期格式或者pattern格式有误!" );
Date parse = null;
try {
parse = getSDF(pattern).parse(dateStr);
} catch (ParseException th) {
ExcpUtils.throwExp(MessageFormat.format("日期解析有误!{0}",
th.getMessage()));
} catch (Throwable th) {
ExcpUtils.throwExp(MessageFormat.format("日期解析未知异常!{0}",
th.getMessage()));
}
return parse;
}
private static boolean judgeStrLength(String str1, String str2){
if(StringUtils.hasLength(str1) && StringUtils.hasLength(str2)){
return str1.trim().length() > 0
&& str1.trim().length() == str2.trim().length();
}
return false;
}
private static SimpleDateFormat getSDF(String pattern){
AssertUtils.assertNonEmpty(pattern, "time pattern should not be null or empty.");
ThreadLocal<SimpleDateFormat> local = timeLocalMaps.get(pattern);
/* 双重检测锁,为timeLocalMaps增加volatile标识,
* 禁止指令重排 */
if(null == local){
synchronized (lockObj){
local = timeLocalMaps.get(pattern);
if(null == local){
local = ThreadLocal.withInitial(()->new SimpleDateFormat(pattern));
timeLocalMaps.put(pattern, local);
}
}
}
return local.get();
}
private void testDate(){
long start = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(100000);
for (int i = 0; i < 1000; i++) {
for(int j = 0; j<100; j++) {
new Thread(() -> {
try {
// 每个子线程单独创建sdf变量
SimpleDateFormat sdf = DateUtils.getSDF("yyyy-MM-dd");
Date parse = null;
try {
parse = sdf.parse("2022-11-10");
} catch (Exception e) {
System.out.println("错误!!!!");
throw new RuntimeException(e);
}
System.out.println("日期是" + parse);
} finally {
countDownLatch.countDown();
}
}, "thread-" + j).start();
}
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end - start)+"ms");
}
public static void main(String[] args) {
Date dateByStr = getDateByStr("2022-11-20", "yyyy-MM-dd");
System.out.println(dateByStr);
String s = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(s);
String s1 = formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.fff");
System.out.println(s1);
}
}
IfElseUtils:
package com.xiaoxu.crawler.utils;
/**
* @author xiaoxu
* @date 2022-11-24 0:51
* crawlerJ:com.xiaoxu.crawler.utils.IfElseUtils
*/
public class IfElseUtils {
/* if-else void-template */
public static void executeBothSide(boolean flag, ActionCallBack callBack){
if(flag){
callBack.actionTrue();
}else{
callBack.actionFalse();
}
}
/* if-else T-value-template */
public static <T> T executeBothSideWithValue(boolean flag, ActionCallBackWithValue<T> callBack){
if(flag){
return callBack.actionTrue();
}else{
return callBack.actionFalse();
}
}
public interface ActionCallBackWithValue<T>{
/* 为真时 */
T actionTrue();
/* 为假时 */
T actionFalse();
}
public interface ActionCallBack{
/* 为真时 */
void actionTrue();
/* 为假时 */
void actionFalse();
}
}
ExcpUtils:
package com.xiaoxu.crawler.utils;
import com.xiaoxu.crawler.excp.AccessParamException;
import com.xiaoxu.crawler.excp.CrawlerForJException;
import org.springframework.util.StringUtils;
/**
* @author xiaoxu
* @date 2022-11-06 16:04
* crawlerJ:com.xiaoxu.crawler.utils.ExcpUtils
*/
public class ExcpUtils {
/* 不为true则抛出异常 */
public static void throwExpIfFalse(boolean result,String msg){
if(StringUtils.hasLength(msg)&&!result){
throw new CrawlerForJException(msg);
}else if(!StringUtils.hasLength(msg)){
throw new AccessParamException(
String.format(
"调用throwExpIfFalse方法的msg不能为空:%s",msg));
}
}
/* 抛出异常的工具方法 */
public static void throwExp(String message){
if(StringUtils.hasLength(message)){
throw new CrawlerForJException(message);
}else{
throw new AccessParamException(
String.format("方法%s的参数不能为空:%s",
ExcpUtils.class.getSimpleName()
+Thread.currentThread().getStackTrace()[1].getMethodName(),
message));
}
}
}
StrUtils:
package com.xiaoxu.crawler.utils;
import org.springframework.util.StringUtils;
import java.text.MessageFormat;
/**
* @author xiaoxu
* @date 2022-11-19 21:52
* crawlerJ:com.xiaoxu.crawler.utils.StringUtils
*/
public class StrUtils {
public static boolean equals(String a, String b){
if(null == a){
return null == b;
}
return a.equals(b);
}
public static int getMatchCount(String str, String subStr){
if(!StringUtils.hasLength(str) || !StringUtils.hasLength(subStr)){
ExcpUtils.throwExp(
MessageFormat.format("getMatchCount's str and subStr should not be null or empty:{0},{1}.",
str, subStr));
}
return StringUtils.countOccurrencesOf(str, subStr);
}
}
AssertUtils:
package com.xiaoxu.crawler.utils;
import com.xiaoxu.crawler.excp.CrawlerForJException;
import org.apache.commons.lang3.ArrayUtils;
/**
* @author xiaoxu
* @date 2022-11-06 15:50
* crawlerJ:com.xiaoxu.crawler.utils.AssertUtils
*/
public class AssertUtils {
/* 校验为真 */
public static void assertTrue(boolean res, String errorMsg){
handlerError(res, errorMsg);
}
/* 校验非空 */
public static <T> void assertNonNull(T obj, String errorMsg){
handlerError(null != obj, errorMsg);
}
/* 校验非null非empty字符串 */
public static <T> void assertNonEmpty(String str, String errorMsg){
handlerError(null != str && !str.isEmpty(), errorMsg);
}
/* 校验非空Array */
public static <T> void assertNonEmptyArray(T[] array, String errorMsg){
handlerError(!ArrayUtils.isEmpty(array), errorMsg);
}
/* 统一异常处理 */
private static void handlerError(boolean flag, String message){
if(!flag){
/* 使用公共异常处理 */
throw new CrawlerForJException(message);
}
}
}
执行结果如下:
12:46:16.779 [main] INFO com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.744 - info] 今天星期是12
12:46:16.782 [main] INFO com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - info] 今天星期是
12:46:16.782 [main] WARN com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - warn] 空指针异常!please check
12:46:16.782 [main] ERROR com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - error] 严重错误!!!参数:,123
12:46:16.782 [main] INFO com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - info] 调用[getYou]方法, 请求参数:[123], 耗时:[2121]ms.
12:46:16.782 [main] WARN com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - warn] 调用[getYou]方法, 请求参数:[123], 耗时:[2121]ms.
12:46:16.782 [main] ERROR com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - error] 调用[getYou]方法, 请求参数:[123], 耗时:[2121]ms.
12:46:16.782 [main] INFO com.xiaoxu.crawler.utils.LogUtils - [2022-12-25 12:46:16.782 - info] 成功!!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/192101.html