jfinal-jfinal日志框架分析

长孙知
2023-12-01

背景介绍

之所以想要写这一篇分享是因为前一段时间看了另一个分享,使用日志打印出完整的sql语句,而不是像jfinal内置的devMode中带”?”的sql语句.Jfinal中使用日志框架输出完整sql语句信息

但是遇到了一个问题,该分享中使用的日志框架是logback,但是我的项目中使用的是jfinal自带的日志框架(即配置了log4j.properties),会打印出来很多无用的日志,当时并不知道怎么配置”日志过滤”,就放弃了该分享中的功能,现在终于解决了这个问题,现分享如下:

问题

分享从几个问题开始:

  • Jfinal中使用的是什么日志框架?如何更改?
  • 应该选用什么框架实现日志过滤的功能?
  • 如何配置日志框架才能实现日志过滤的功能?

jfinal使用的是什么日志框架?默认实现是什么?如何更改?

jfinal使用的是封装了一层的日志框架,可以兼容其余所有日志框架,为何这么说,看源码,jfinal源码中有一个接口ILogFactory,一个抽象类Log,jfinal源代码中使用的日志工具就是Log的子类.为什么说jfinal可以兼容其余所有日志框架呢?看下jfinal提供的Log实现类,有两个,一个JdkLog,一个Log4jLog,从名字就可以看出,一个是封装Jdk默认log,一个是封装log4j的log,部分代码如下:

public class Log4jLog extends Log {

   private org.apache.log4j.Logger log;
   private static final String callerFQCN = Log4jLog.class.getName();

   Log4jLog(Class<?> clazz) {
      log = org.apache.log4j.Logger.getLogger(clazz);
   }

   Log4jLog(String name) {
      log = org.apache.log4j.Logger.getLogger(name);
   }

   public static Log4jLog getLog(Class<?> clazz) {
      return new Log4jLog(clazz);
   }

   public static Log4jLog getLog(String name) {
      return new Log4jLog(name);
   }

   public void info(String message) {
      log.log(callerFQCN, Level.INFO, message, null);
   }
   ...
 }

就是封装了一个org.apache.log4j.Logger,所有的操作调用log4j的log完成

jfinal的默认实现又是什么呢?

初始化的代码在抽象类Log中

public abstract class Log {

   private static ILogFactory defaultLogFactory = null;

   static {
      init();
   }

   static void init() {
      if (defaultLogFactory == null) {
         try {
            Class.forName("org.apache.log4j.Logger");
            Class<?> log4jLogFactoryClass = Class.forName("com.jfinal.log.Log4jLogFactory");
            defaultLogFactory = (ILogFactory)log4jLogFactoryClass.newInstance();   // return new Log4jLogFactory();
         } catch (Exception e) {
            defaultLogFactory = new JdkLogFactory();
         }
      }
   }
   ...
 }

如果可以加载log4j的jar包,就使用log4j,否则使用JdkLog

如何更改日志框架呢?

在configConstant中配置即可

@Override
public void configConstant(Constants me) {
   ...
   me.setLogFactory(new Slf4jLogFactory());
   ...
}

其中Slf4jLogFactory类直接使用了cn.dreampie的代码,表示感谢,maven如下

<dependency>
    <groupId>cn.dreampie</groupId>
    <artifactId>jfinal-slf4j</artifactId>
    <version>0.1</version>
</dependency>

应该选用什么框架实现日志过滤的功能?

在此之前需要了解以下日志框架体系,日志框架体系介绍

从上面已经看到,日志门面使用的是slf4j,便于修改,但是底层的日志使用什么实现呢?log4j最新的一版是2012的,太老了直接淘汰,查了下比较常用的是log4j2和logback,从网上查到的资料个人感觉log4j2好用点,就决定使用log4j2,需要一共四个依赖.

<!--slf4j及log4j日志-->
<!--门面-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
</dependency>
<!--桥接器:告诉slf4j使用Log4j2-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>${log4j2.version}</version>
    <exclusions>
        <exclusion>
            <artifactId>slf4j-api</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
    </exclusions>
</dependency>
<!--具体实现,log4j2-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j2.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j2.version}</version>
</dependency>
<log4j2.version>2.9.1</log4j2.version>
<!--不能升级为1.8.*,log4j2的2.9.1版本依赖1.7.25,使用1.8提示No SLF4J providers were found-->
<slf4j.version>1.7.25</slf4j.version>

注意:slf4j1.8.*1.7.*获取桥接器的方式不一致,log4j2的2.9.1版本只实现了slf4j1.7.*版本的桥接器.若修改slf4j版本为1.8.*则不兼容

如何配置日志框架才能实现日志过滤的功能

由于日志选择使用slf4j+log4j2,其实配置就是配置log4j2,网上关于如何配置log4j2的文章很多,都可以查到.

我配置的时候遇到一个坑,log4j2有两种模式,一种strict,一种非strict,strict模式是严格按照xsd标准的配置文件,当时觉得strict模式符合xsd标准,idea也不会报error,就尽力想使用strict模式配置,后来发现一些功能配置实现不了,而且网上的文章多数都是使用非strict模式配置,最后就放弃了,决定使用非strict模式配置,于是idea一打开log4j2.xml文件,就全是error,真是丑

总结

  • jfinal抽象了日志实现,可以兼容任何日志框架
  • 使用slf4j+log4j2实现日志框架,当时要注意jar包版本,注意兼容问题
  • 使用非strict模式配置log4j2,虽然丑,但是能用

当时下定决心修改日志框架是因为要让日志打印sql语句,最后该功能当然是实现了,不过使用的并不是文章开头链接中提到的方法,而是—–>druid,下一篇分享写下如何配置druid

参考

 类似资料: