自行实现的jar包中,日志库的适配实现
日常情况下,我们自己都会自行实现一些基础的jar包,如dao包、service包或一些其他完成特定功能的jar包。如果没有一套调试日志信息,出现问题时想查找问题非常不方便。可能大多数小伙伴都会有自己的一套查找问题的方法。
但在jar包中添加日志信息输出还是有必要的。
我们自己实现的jar包中不能写死使用哪一种日志库输出,必竟现在有好几个比较流行的日志库。jdk中自带有一个,log4j ,logback,apache logging,slf4j等都是效率比较高的日志信息。有这么多可用的日志库,我们完全没有必要自行实现一个日志库。
在自己实现的jar包中,可以实现一个适配,我们将jar提供给别人使用时,别人在使用的过程中如果使用的是slf4j或logback,我们的jar包可以做到自行适配相应的日志库,这种方案是比较完美可行的。
1.实现接口,日志操作接口
public interface Log {
boolean isDebugEnabled();
void debug(String msg);
void debug(String msg, Throwable e);
boolean isErrorEnabled();
void error(String msg, Throwable e);
void error(String msg);
boolean isInfoEnabled();
void info(String msg);
boolean isWarnEnabled();
void warn(String msg);
void warn(String msg, Throwable e);
}
与大多数日志库的接口一样,日志输出分为debug,info,error,warn级别,同理也做拉相应级别的日志输出开关。
2.SLF4J日志库的适配实现
public class SLF4JImpl implements Log {
private static final String callerFQCN = SLF4JImpl.class.getName();
private static final Logger testLogger = LoggerFactory.getLogger(SLF4JImpl.class);
static {
// if the logger is not a LocationAwareLogger instance, it can not get correct stack StackTraceElement
// so ignore this implementation.
if (!(testLogger instanceof LocationAwareLogger)) {
throw new UnsupportedOperationException(testLogger.getClass() + " is not a suitable logger");
}
}
private LocationAwareLogger log;
public SLF4JImpl(LocationAwareLogger log){
this.log = log;
}
public SLF4JImpl(String loggerName){
this.log = (LocationAwareLogger) LoggerFactory.getLogger(loggerName);
}
public boolean isDebugEnabled() {
return log.isDebugEnabled();
}
public void debug(String msg) {
log.log(null, callerFQCN, LocationAwareLogger.DEBUG_INT, msg, null, null);
}
public void debug(String msg, Throwable e) {
log.log(null, callerFQCN, LocationAwareLogger.DEBUG_INT, msg, null, e);
}
public boolean isErrorEnabled() {
return log.isErrorEnabled();
}
public void error(String msg, Throwable e) {
log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, e);
}
public void error(String msg) {
log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, null);
}
public boolean isInfoEnabled() {
return log.isInfoEnabled();
}
public void info(String msg) {
log.log(null, callerFQCN, LocationAwareLogger.INFO_INT, msg, null, null);
}
public boolean isWarnEnabled() {
return log.isWarnEnabled();
}
public void warn(String msg) {
log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, null);
}
public void warn(String msg, Throwable e) {
log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, e);
}
}
从上述代码可以看到,SLF4J的日志库适配实现,类的内部实现还是以slf4j的内部对象来完成相应的日志输出,与日志级别开关的控制。最重要的一句代码是在静态代码块中,对创建出来的testLogger对象进行对象的比对。
3.日志工厂实现,获取具体的日志操作实现类
public final class LogFactory {
private static Constructor logConstructor;
static {
String logType= System.getProperty("logType");
if(logType != null){
if(logType.equalsIgnoreCase("slf4j")){
tryImplementation("org.slf4j.Logger", "logging.slf4j.SLF4JImpl");
}
}
// 优先选择log4j,而非Apache Common Logging. 因为后者无法设置真实Log调用者的信息
tryImplementation("org.slf4j.Logger", "logging.slf4j.SLF4JImpl");
if (logConstructor == null) {
try {
logConstructor = NoLoggingImpl.class.getConstructor(String.class);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}
private static void tryImplementation(String testClassName, String implClassName) {
if (logConstructor != null) {
return;
}
try {
Resources.classForName(testClassName);
Class implClass = Resources.classForName(implClassName);
logConstructor = implClass.getConstructor(new Class[] { String.class });
Class<?> declareClass = logConstructor.getDeclaringClass();
if (!Log.class.isAssignableFrom(declareClass)) {
logConstructor = null;
}
try {
if (null != logConstructor) {
logConstructor.newInstance(LogFactory.class.getName());
}
} catch (Throwable t) {
logConstructor = null;
//t.printStackTrace();
}
} catch (Throwable t) {
//t.printStackTrace();
}
}
public static Log getLog(Class clazz) {
return getLog(clazz.getName());
}
public static Log getLog(String loggerName) {
try {
System.out.println(logConstructor);
return (Log) logConstructor.newInstance(loggerName);
} catch (Throwable t) {
throw new RuntimeException("Error creating logger for logger '" + loggerName + "'. Cause: " + t, t);
}
}
}
- 使用时,通过LogFactory.getLog方法来获取log对象,进行日志输出。
- 在静态代码块中,对系统中使用的日志库进行探测,优先选择slf4j日志库。
- 对于系统中没有匹配到相应的日志,则会适配一个NoLoggingImpl空的日志输出控制对象
4.maven依赖
代码实现需要使用slf4j中的api,所以在pom.xml中需要添加上slf4j包的依赖,但添加上此依赖后,说明我们的jar包就不在是一个比较干净的包实现,因此需要对jar包进行一定范围内的控制。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
<optional>true</optional>
</dependency>
optional选项,代表的是如果jar依赖者如果显示的调用则会添加上相关的jar依赖,否则不会进行jar的依赖
5.无日志库依赖时测试
外部使用者没有添加任何的日志输出,则不会有相应的jar包来实现
输出结果:
public logging.nologgin.NoLoggingImpl(java.lang.String)
结果中可以查看到,日志库使用的是NoLoggingImpl一个内部自行实现的空的日志输出
6.有日志库依赖时
这里的测试使用的是maven项目,相应的pom文件中,加入logback依赖包。
并且在resource目录下,有相应的logback.xml日志配置文件。
输出结果:
public logging.slf4j.SLF4JImpl(java.lang.String)
结果中可以看到,我们的jar包中,已经自行实现SLF4J日志库的适配
至此一个日志库的自适应适配完成实现 ,代码中只是给出拉SLF4J的日志实现,如果小伙伴们有其他需要可自行实现其他的日志库
相应的代码实现,可以点击以下链接进行下载。
[日志库适配简单实现方式](
自行实现的jar包中,日志库的适配实现的更多相关文章
- 使用 jpype 库实现 Python 调用 java 的 jar 包中的功能
一.what's the JPype JPype 是一个能够让 python 代码方便地调用 Java 代码的工具.在某些时候 java 的能力更强,我们可以用 java 写一个模块的功能然后用 Py ...
- java 执行 jar 包中的 main 方法
java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...
- html或者jsp页面引用jar包中的js文件
一,页面上引用jar包中的js文件的方法 使用java web框架AppFuse的时候发现,jquery.bootstrap等js框架都封装到jar包里面了.这些js文件通过一个wro4j的工具对其进 ...
- 判断一个类到底是从哪个jar包中调用的工具类
项目中使用的jar包较多时,会出现jar冲突的情况,有时候很难判断当前使用的这个类是从哪个jar包中调用的.因为一般我们只能看到jar包的名称,不清楚其中的类的目录结构. 这个类的作用就是说明当前调用 ...
- 如何在大量jar包中搜索特定字符
欢迎关注我的社交账号: 博客园地址: http://www.cnblogs.com/jiangxinnju/p/4781259.html GitHub地址: https://github.com/ji ...
- 读取Jar包中的资源问题探究
最近在写一个可执行jar的程序,程序中包含了2个资源包,一个是images,一个是files.问题来了,在Eclipse里开发的时候,当用File类来获取files下面的文件时,没有任何问题.但是当程 ...
- 【解惑】深入jar包:从jar包中读取资源文件
[解惑]深入jar包:从jar包中读取资源文件 http://hxraid.iteye.com/blog/483115 TransferData组件的spring配置文件路径:/D:/develop/ ...
- java 从jar包中读取资源文件
在代码中读取一些资源文件(比如图片,音乐,文本等等),在集成环境(Eclipse)中运行的时候没有问题.但当打包成一个可执行的jar包(将资源文件一并打包)以后,这些资源文件找不到,如下代码: Jav ...
- 27 Java动态加载第三方jar包中的类
我加载的方法是://参数fileName是jar包的路径,processorName 是业务类的包名+类名public static A load(String fileName, String pr ...
随机推荐
- spring boot:用zxing生成二维码,支持logo(spring boot 2.3.2)
一,zxing是什么? 1,zxing的用途 如果我们做二维码的生成和扫描,通常会用到zxing这个库, ZXing是一个开源的,用Java实现的多种格式的1D/2D条码图像处理库. zxing还可以 ...
- Linux如何在vim里搜索关键字
例如搜索 the写法:/the +回车 /+关键字 ,回车即可.此为从文档当前位置向下查找关键字,按n键查找关键字下一个位置: ?+关键字,回车即可.此为从文档挡圈位置向上查找关键字,按n键向 ...
- centos8平台使用ethtool配置网卡
一,ethtool命令所属的包 [root@centos8 liuhongdi]# whereis ethtool ethtool: /usr/sbin/ethtool /usr/share/man/ ...
- ubuntu基于VSCode的C++编程语言的构建调试环境搭建指南
ubuntu基于VSCode的C++编程语言的构建调试环境搭建指南 首先安装g++ sudo apt install g++ 检查是否安装成功: 在插件栏安装插件c/c++.code runner: ...
- 【API管理 APIM】APIM中如何配置使用URL路径的方式传递参数(如由test.htm?name=xxx 变为test\xxx)
问题描述 在默认的URL传递参数中,我们使用的是https://test01.azure-api.cn/echo/resource?param1=sample¶m2=testname这 ...
- windows注册redis为服务,zookeeper为服务
windows注册redis为服务,zkserver为服务 1.redis部分 通过redis内置工具安装 进入redis安装目录 1.shift+鼠标右键打开菜单,点击"在此处打开命令窗口 ...
- 常见ascii码记忆
常见字符的ASCII码值如下:空格的ASCII码值为32:数字0到9的ASCII码值分别为48到57:大写字母"A"到"Z"的ASCII码值分别为65到90:小 ...
- javaScript 必会基础知识
1.JavaScript是一种浏览器解析的轻量级脚本语言. 2.html.jsp等内部js代码写在<script></script>之间:外部js文件中书写js代码不能有< ...
- Kubernetes K8S之调度器kube-scheduler详解
Kubernetes K8S之调度器kube-scheduler概述与详解 kube-scheduler调度概述 在 Kubernetes 中,调度是指将 Pod 放置到合适的 Node 节点上,然后 ...
- 【django-simpleui】‘simpletags‘ is not a registered tag library报错的解决方法
1:创建 templatetags文件夹 2:创建simpletags.py文件将内容粘贴进去,在下面 3:setting.py添加文件指定: 1 TEMPLATES = [ 2 { 3 'BACK ...