自行实现的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 ...
随机推荐
- jmeter_04_常用取样器
目录 常用取样器详解 http取样器 1.1 基本配置 1.2 高级配置 jdbc取样器 2.1 JDBC Connection Configuration 2.1.1 **Variable Name ...
- rabbitmq 交换机模式一 广播模式 fanout
<?php require_once "./vendor/autoload.php"; use PhpAmqpLib\Connection\AMQPStreamConnect ...
- centos8上配置openssh的安全
一,openssh服务版本号的查看 1,查看当前sshd的版本号 : [root@yjweb ~]# sshd --help unknown option -- - OpenSSH_7.8p1, Op ...
- Spring笔记(4) - Spring的编程式事务和声明式事务详解
一.背景 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作 ...
- poj1655 Balancing Act (dp? dfs?)
Balancing Act Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14247 Accepted: 6026 De ...
- 闭包 - Js函数笔记
闭包 当函数被保存到外部时,将会生成闭包 闭包会导致原有作用域链不释放,造成内存泄漏 类似的代码就叫闭包 闭包的运行作用域 代码 a被执行,b被定义并保存出来 a结束,b被执行时,a的执行期上下文指向 ...
- 2020-2021-1 20209306 《linux内核原理与分析》第一周作业
学习过程中遇到了如下的问题,通过探索找到了可以解决的方法 1.如何退回主目录或者编辑某个文件夹. 使用cd/home可以退回主目录,这里注意的是绝对路径和相对路径的区别,在学习时我试图切换到home目 ...
- HelloGitHub 开源月刊(第 55 期):终端“百战天虫”,来战?
兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...
- Linux配置和管理设备映射多路径multipath
(一)多路径管理软件的由来 在企业中,服务器与存储通常是分开放置的,服务器上的硬盘通常用来安装操作系统和应用软件,业务数据则是存储在单独的存储设备上,那么,服务器与存储是如何连接的呢?根据存储协议,经 ...
- Luogu P2447 [SDOI2010]外星千足虫
题意 给定 \(n\) 个变量和 \(m\) 个异或方程,求最少需要多少个才能确定每个变量的解. \(\texttt{Data Range:}1\leq n\leq 10^3,1\leq m\leq ...