​ 日常情况下,我们自己都会自行实现一些基础的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包中,日志库的适配实现的更多相关文章

  1. 使用 jpype 库实现 Python 调用 java 的 jar 包中的功能

    一.what's the JPype JPype 是一个能够让 python 代码方便地调用 Java 代码的工具.在某些时候 java 的能力更强,我们可以用 java 写一个模块的功能然后用 Py ...

  2. java 执行 jar 包中的 main 方法

    java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...

  3. html或者jsp页面引用jar包中的js文件

    一,页面上引用jar包中的js文件的方法 使用java web框架AppFuse的时候发现,jquery.bootstrap等js框架都封装到jar包里面了.这些js文件通过一个wro4j的工具对其进 ...

  4. 判断一个类到底是从哪个jar包中调用的工具类

    项目中使用的jar包较多时,会出现jar冲突的情况,有时候很难判断当前使用的这个类是从哪个jar包中调用的.因为一般我们只能看到jar包的名称,不清楚其中的类的目录结构. 这个类的作用就是说明当前调用 ...

  5. 如何在大量jar包中搜索特定字符

    欢迎关注我的社交账号: 博客园地址: http://www.cnblogs.com/jiangxinnju/p/4781259.html GitHub地址: https://github.com/ji ...

  6. 读取Jar包中的资源问题探究

    最近在写一个可执行jar的程序,程序中包含了2个资源包,一个是images,一个是files.问题来了,在Eclipse里开发的时候,当用File类来获取files下面的文件时,没有任何问题.但是当程 ...

  7. 【解惑】深入jar包:从jar包中读取资源文件

    [解惑]深入jar包:从jar包中读取资源文件 http://hxraid.iteye.com/blog/483115 TransferData组件的spring配置文件路径:/D:/develop/ ...

  8. java 从jar包中读取资源文件

    在代码中读取一些资源文件(比如图片,音乐,文本等等),在集成环境(Eclipse)中运行的时候没有问题.但当打包成一个可执行的jar包(将资源文件一并打包)以后,这些资源文件找不到,如下代码: Jav ...

  9. 27 Java动态加载第三方jar包中的类

    我加载的方法是://参数fileName是jar包的路径,processorName 是业务类的包名+类名public static A load(String fileName, String pr ...

随机推荐

  1. jmeter_04_常用取样器

    目录 常用取样器详解 http取样器 1.1 基本配置 1.2 高级配置 jdbc取样器 2.1 JDBC Connection Configuration 2.1.1 **Variable Name ...

  2. rabbitmq 交换机模式一 广播模式 fanout

    <?php require_once "./vendor/autoload.php"; use PhpAmqpLib\Connection\AMQPStreamConnect ...

  3. centos8上配置openssh的安全

    一,openssh服务版本号的查看 1,查看当前sshd的版本号 : [root@yjweb ~]# sshd --help unknown option -- - OpenSSH_7.8p1, Op ...

  4. Spring笔记(4) - Spring的编程式事务和声明式事务详解

    一.背景 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作 ...

  5. poj1655 Balancing Act (dp? dfs?)

    Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14247   Accepted: 6026 De ...

  6. 闭包 - Js函数笔记

    闭包 当函数被保存到外部时,将会生成闭包 闭包会导致原有作用域链不释放,造成内存泄漏 类似的代码就叫闭包 闭包的运行作用域 代码 a被执行,b被定义并保存出来 a结束,b被执行时,a的执行期上下文指向 ...

  7. 2020-2021-1 20209306 《linux内核原理与分析》第一周作业

    学习过程中遇到了如下的问题,通过探索找到了可以解决的方法 1.如何退回主目录或者编辑某个文件夹. 使用cd/home可以退回主目录,这里注意的是绝对路径和相对路径的区别,在学习时我试图切换到home目 ...

  8. HelloGitHub 开源月刊(第 55 期):终端“百战天虫”,来战?

    兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...

  9. Linux配置和管理设备映射多路径multipath

    (一)多路径管理软件的由来 在企业中,服务器与存储通常是分开放置的,服务器上的硬盘通常用来安装操作系统和应用软件,业务数据则是存储在单独的存储设备上,那么,服务器与存储是如何连接的呢?根据存储协议,经 ...

  10. Luogu P2447 [SDOI2010]外星千足虫

    题意 给定 \(n\) 个变量和 \(m\) 个异或方程,求最少需要多少个才能确定每个变量的解. \(\texttt{Data Range:}1\leq n\leq 10^3,1\leq m\leq ...