spring5新特性日志体系

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: spring5新特性日志体系 主流的log技术名词 1.jul 2.log4j 3.jcl jcl源码分析: 虽然Log4JLogger是jcl的jar包中的类,但是该Log4JLogger类,依赖了

spring5新特性日志体系

主流的log技术名词
1.jul
java自带的一个日志记录的技术,直接使用
java.util.logging.Logger
2.log4j
//log4j依赖
<dependency>
    <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
       <version>1.2.17</version>
</dependency>

//log4配置文件
log4j.rootLogger=info, stdout
#mybatis的sql级别(结果的日志级别为TRACE,SQL 语句的日志级别为DEBUG)
log4j.logger.com.log.dao=TRACE  
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

//log4j测试类
public static void main(String[] args) {
       Logger log4j = Logger.getLogger("log4j");
    log4j.info("log4j");
}

//输出
2019-09-03 11:17:06,273 INFO [log4j] - log4j
log4j特点:
可以不需要依赖第三方的技术,直接记录日志。
3.jcl
//jcl依赖
<dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.2</version>
</dependency>

//jcl测试类
public static void main(String[] args) {
    Log jcl = LogFactory.getLog("jcl");
    jcl.info("jcl");
}

//输出
(1):2019-09-03 11:23:54,470 INFO [jcl] - jcl

(2):九月 03, 2019 11:24:43 上午 jcl main
      信息: jcl
这个jcl什么情况下会有不同的输出?
1.当项目有logj4的依赖的时候,就会输出(1)信息。
2.当项目没有log4j依赖的时候,就会使用java自带的日志技术jul输出(2)信息。
  • jcl源码分析:
#LogFactory
public static Log getLog(String name) throws LogConfigurationException {
    //通过Factory获取instance实例
    return getFactory().getInstance(name);
}

#LogFactoryImpl
public Log getInstance(String name) throws LogConfigurationException {
    //一开始没有缓存,所以为null
    Log instance = (Log) instances.get(name);
    if (instance == null) {
        //这里是重点,创建logger实例
        instance = newInstance(name);
        //放入到缓存中
        instances.put(name, instance);
    }
    return instance;
}

protected Log newInstance(String name) throws LogConfigurationException {
    Log instance;
    try {
        if (logConstructor == null) {
            //重要代码,发现log实现类
            instance = discoverLogImplementation(name);
        }
        else {
            Object params[] = { name };
             instance = (Log) logConstructor.newInstance(params);
        }
        if (logMethod != null) {
             Object params[] = { this };
             logMethod.invoke(instance, params);
        }
        return instance;
    }
}

private Log discoverLogImplementation(String logCategory)
        throws LogConfigurationException {
   if (isDiagnosticsEnabled()) {
        logDiagnostic("Discovering a Log implementation...");
    }
    initConfiguration();
    
    //需要返回的对象
    Log result = null;
    
    //查看用户是否指定要使用的日志实现
    String specifiedLogClassName = findUserSpecifiedLogClassName();
    if (specifiedLogClassName != null) {
        if (isDiagnosticsEnabled()) {
            logDiagnostic("");
        }
        result = createLogFromClass(specifiedLogClassName, logCategory,  true);
        if (result == null) {
            StringBuffer messageBuffer =  new StringBuffer("User-specified log class '");
            messageBuffer.append(specifiedLogClassName);
            messageBuffer.append("' cannot be found or is not useable.");

            // Mistyping or misspelling names is a common fault.
            // Construct a good error message, if we can
            informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LOG4J_LOGGER);
            informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_JDK14_LOGGER);
            informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LUMBERJACK_LOGGER);
            informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_SIMPLE_LOGGER);
            throw new LogConfigurationException(messageBuffer.toString());
        }
        return result;
    }
    if (isDiagnosticsEnabled()) {
        logDiagnostic("");
    }
    //如果用户没有指定日志实现类,jcl使用默认的实现类(4个),然后遍历依次创建对应的log实现类。
    for(int i=0; i<classesToDiscover.length && result == null; ++i) {
        result = createLogFromClass(classesToDiscover[i], logCategory, true);
    }
    if (result == null) {
        throw new LogConfigurationException("");
    }
    return result;
}

//jcl内部默认的4个log实现类。
private static final String[] classesToDiscover = {
    "org.apache.commons.logging.impl.Log4JLogger",
    "org.apache.commons.logging.impl.Jdk14Logger",
    "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
    "org.apache.commons.logging.impl.SimpleLog"
};

//根据class创建log对象
private Log createLogFromClass(String logAdapterClassName,
                               String logCategory,
                               boolean affectState)
    throws LogConfigurationException {
    
    Object[] params = { logCategory };
    Log logAdapter = null;
    Constructor constructor = null;

    Class logAdapterClass = null;
    ClassLoader currentCL = getBaseClassLoader();

    for(;;) {       
        logDiagnostic("Trying to load '" + logAdapterClassName + "' from classloader " + objectId(currentCL));
        try {           
            Class c;
            try {
                //通过class.forName加载log类
                c = Class.forName(logAdapterClassName, true, currentCL);
            } catch (ClassNotFoundException originalClassNotFoundException) {      
                //表示找不到类(因为用户可能指定类log的实现类)       
                try {                   
                    c = Class.forName(logAdapterClassName);
                } catch (ClassNotFoundException secondaryClassNotFoundException) {                 
                    break;
                }
            }
            //拿到c的构造方法对象。然后通过构造对象来创建对象。(有参构造方法)
            constructor = c.getConstructor(logConstructorSignature);
            Object o = constructor.newInstance(params);       
            
            if (o instanceof Log) {
                logAdapterClass = c;
                logAdapter = (Log) o;
                break;
            }     
            handleFlawedHierarchy(currentCL, c);
        } catch (NoClassDefFoundError e) {
           
            String msg = e.getMessage();
            logDiagnostic("");
            break;
        } catch (ExceptionInInitializerError e) {         
            String msg = e.getMessage();
            logDiagnostic("");
            break;
        } catch (LogConfigurationException e) {           
            throw e;
        } catch (Throwable t) {
            handleThrowable(t);
            handleFlawedDiscovery(logAdapterClassName, currentCL, t);
        }
        if (currentCL == null) {
            break;
        }
        currentCL = getParentClassLoader(currentCL);
    }
    //返回创建的对象
    return logAdapter;
}
通过分析jcl的代码可以得到:
jcl本身不实现日志记录,但是提供了记录日志的抽象方法即接口(info,debug,error.......)
底层通过一个数组存放具体的日志框架的类名,然后循环数组依次去匹配这些类名是否在项目中被依赖了,如果找到被依赖的则直接使用,所以他有先后顺序。
下图为jcl中存放日志技术类名的数组,默认有四个,后面两个可以忽略。
在这里插入图片描述
上面的代码81行就是通过一个类名去load一个class,如果load成功则直接new出来并且返回使用。如果没有load到class这循环第二个,直到找到为止。
可以看到这里的循环条件必须满足result不为空,也就是如果没有找到具体的日志依赖则继续循环,如果找到则条件不成立,不进行循环了。
总结:顺序log4j>jul
  • 虽然Log4JLogger是jcl的jar包中的类,但是该Log4JLogger类,依赖了log4j的类,当你没有引入log4j的依赖的时候,在创建Log4JLogger类,就会失败。
  • 下图是在没有引入log4j依赖的情况下,Log4JLogger类的情况图:
  • 在这里插入图片描述
  • 因为jul是java自带的日志类,所以在java环境下,jcl就算在创建log4j失败的情况下,也会去创建Jdk14Logger。可以看到Jdk14Logger是依赖了jul的。下图是Jdk14Logger的类图:
  • 在这里插入图片描述
jcl特点:
他不直接记录日志,他是通过第三方记录日志(jul)。
jcl是一个接口,默认有4个log实现类。
4.slf4j
slf4j他也不记录日志,通过绑定器绑定一个具体的日志记录来完成日志记录
官网: https://www.slf4j.org/
//slf4j依赖
<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>1.7.25</version>
</dependency>
  • 在只添加了slf4j依赖,而没有添加任意一个绑定器,日志是不会打印的。控制台会输出warn信息,如下图:
  • 在这里插入图片描述
//slf4j依赖
<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>1.7.25</version>
</dependency>

<!--slf4jbind绑定器,将slf4j绑定到jul-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.25</version>
</dependency>

<!--slf4jbind绑定器,将slf4j绑定到log4j-->
<!--<dependency>-->
<!--    <groupId>org.slf4j</groupId>-->
<!--    <artifactId>slf4j-log4j12</artif
<!--    <version>1.7.5</version>-->
<!--</dependency>-->

<!--slf4jbind绑定器,将slf4j绑定到jcl-->
<!--<dependency>-->
<!--    <groupId>org.slf4j</groupId>-->
<!--    <artifactId>slf4j-jcl</artifactI
<!--    <version>1.7.25</version>-->
<!--</dependency>-->
  • slf4j提供了很多的绑定器,有log4j,jul,jcl。
  • 当引入了jul绑定器之后,slf4j就能打印日志了,如下图:
  • 在这里插入图片描述

总结:

  1. slf4j需要打印日志,就一定需要引入绑定器。slf4j提供了很多的绑定器,有jul,jcl,log4j等。
  2. slf4j如果引入了jcl绑定器,因为jcl也是一个接口,jcl会加载log4j,jul。
  1. 如果你想使用log4j,也需要引入log4j的依赖,log4j的配置文件
  2. 如果你不引入log4j的依赖,就默认使用jul
  1. slf4j如果引入了log4j绑定器,需要log4j的配置文件(这个时候不用引入log4j的依赖了,因为该绑定器已经帮我们引入了)
  • 问题:有这样的一个业务系统:
  • 项目A,是使用了slf4j打印日志,然后通过slf4j绑定器,绑定到jul,然后使用jul打印日志。
  • 项目A使用了spring框架,但是spring框架使用jcl打印日志,spring引入了log4j依赖,使得spring框架是用log4j打印日志。
  • 这样的话,项目A就出现了多个日志框架打印日志了,那就很混乱,现在要求项目A只能使用一种日志框架技术,这个要怎么处理?
//项目A的依赖
//log4j
<dependency>
   <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

//jcl
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

//slf4j
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>

<!--slf4jbind绑定器,将slf4j绑定到jul-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.25</version>
</dependency>
  • 就引入上面的依赖jar包,项目就会有两种日志输出,如下图所示:
  • 在这里插入图片描述

解决方案:

  1. 可以通过修改slf4j的绑定器,直接改用slf4j的log4j绑定器。
因为使用slf4j绑定到log4j,只需要简单的引入一个依赖即可。
  1. 使用slf4j的桥接器,将spring使用jcl打印日志这步切断,将jclj桥接到slf4j,然后再走项目A的日志打印。
因为使用jcl桥接到slf4j,只需要简单的引入一个依赖即可。
//增加下面这个依赖即可:
<!--slf4j桥接器,将jcl桥接到slf4j-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>
  • 当使用了jcl-over-slf4j桥接器之后,可以使得jcl桥接到slf4j,然后再走slf4j这边的日志输出。从而实现将spring框架的日志输出,改为了slf4j-->jul
  • 在这里插入图片描述
  • 改进后的日志打印流程图如下:
  • 在这里插入图片描述

各种日志技术的关系和作用

  • 在这里插入图片描述

spring5新特性日志体系

Spring4当中依赖jcl,即Spring4当中采用的日志技术是jcl:commons-logging,即默认使用jul;加入log4j依赖和配置,即可切换为log4j
Spring5当中也是使用了jcl:spring-jcl,是重写为了jul框架。spring5使用的spring的jcl(spring改了jcl的代码)来记录日志的,但是jcl不能直接记录日志,采用循环优先的原则。
spring-jcl源码解析
#AbstractApplicationContext
protected final Log logger = LogFactory.getLog(getClass());

#LogFactory(spring-jcl包下)
public static Log getLog(Class<?> clazz) {
    return getLog(clazz.getName());
}

public static Log getLog(String name) {
    switch (logApi) {
        //log4j2
        case LOG4J:
            return Log4jDelegate.createLog(name);
        //slf4j
        case SLF4J_LAL:
            return Slf4jDelegate.createLocationAwareLog(name);
        case SLF4J:
            return Slf4jDelegate.createLog(name);
        default:
            //默认是jul
            return JavaUtilDelegate.createLog(name);
    }
}

//默认是jul
private static LogApi logApi = LogApi.JUL;
//静态代码块,在类初始化的时候执行
static {
    ClassLoader cl = LogFactory.class.getClassLoader();
    try {
        // Try Log4j 2.x API(尝试加载log4j2)
        cl.loadClass("org.apache.logging.log4j.spi.ExtendedLogger");
        logApi = LogApi.LOG4J;
    }
    catch (ClassNotFoundException ex1) {
        try {
            // Try SLF4J 1.7 SPI(尝试加载slf4j)
            cl.loadClass("org.slf4j.spi.LocationAwareLogger");
            logApi = LogApi.SLF4J_LAL;
        }
        catch (ClassNotFoundException ex2) {
            try {
                // Try SLF4J 1.7 API(尝试加载slf4j)
                cl.loadClass("org.slf4j.Logger");
                logApi = LogApi.SLF4J;
            }
            catch (ClassNotFoundException ex3) {
                // Keep java.util.logging as default(如果都没有,就保持使用默认的jul)
            }
        }
    }
}
从上面spring5的源码可以看到,spring5使用的日志是spring-jcl,默认是jul,然后会依次加载log4j2,slf4j。在都加载不到的情况下,就使用默认的jul日志技术了。
因为spring5使用的是log4j2,所以在加入了log4j的依赖和配置文件,是不生效的。
  • spring5使用log4j2日志技术,需要加入的依赖和配置文件。
<!-- spring5的依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.9.RELEASE</version>
</dependency>

<!-- log4j2依赖 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.8.2</version>
</dependency>

<!-- log4j2.xml配置文件 -->
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
   <Appenders>
       <Console name="Console" target="SYSTEM_OUT">
           <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
       </Console>
   </Appenders>
   <Loggers>
       <Root level="info">
           <AppenderRef ref="Console"/>
       </Root>
   </Loggers>
</Configuration>
  • 要将spring5改用log4j来记录日志,怎么实现?
  • 1.引入slf4j依赖,然后slf4j绑定log4j,并添加log4j的配置文件。
<!-- spring5的依赖 -->
<dependency>
      <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.9.RELEASE</version>
</dependency>

<!--slf4j依赖(可省略)-->
<dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
       <version>1.7.25</version>
</dependency>

<!--slf4jbind绑定器,将slf4j绑定到log4j(已经包含了slf4j和log4j的依赖)-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.5</version>
</dependency>

扩展:

Mybatis日志体系

  • mybatis的日志技术实现
  • 在这里插入图片描述
#LogFactory

private static void tryImplementation(Runnable runnable) {
    //关键代码  logConstructor == null 没有找到实现则继续找
     if (logConstructor == null) {
       try {
             runnable.run();
       } catch (Throwable t) {
             // ignore
       }
     }
}

tryImplementation(new Runnable() {
    @Override
    public void run() {
        useSlf4jLogging();
    }
});

public static synchronized void useSlf4jLogging() {
     setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
}

private static void setImplementation(Class<? extends Log> implClass) {
  try {
        Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
        Log log = candidate.newInstance(LogFactory.class.getName());
        if (log.isDebugEnabled()) {
              log.debug("Logging initialized using '" + implClass + "' adapter.");
        }
        logConstructor = candidate;
  } catch (Throwable t) {
        throw new LogException("Error setting Log implementation.  Cause: " + t, t);
  }
}
具体实现类
mybatis提供很多日志的实现类,用来记录日志,取决于初始化的时候load到的class
  • jcl实现
  • 在这里插入图片描述
  • log4j2实现
  • 在这里插入图片描述
  • jul实现
  • 在这里插入图片描述
mybaits缓存问题:
1.mybaits在整合spring框架的时候,一级缓存会失效,原因是mybatis一级缓存是基于sqlSession的,整合了spring之后,spring会管理sqlSession,在查询完之后,会帮我们关闭sqlSession,所以导致缓存失效了。

2.mybatis的二级缓存。开启也是很简单在对应的mapper接口中加上@CacheNamespace注解即可。
备注:mybatis的二级缓存会有一个很大的坑。
因为mybatis的二级缓存是基于命名空间来实现了。当在不同的mapper接口操作了同一张表,这个就会有问题了,A接口更新了数据,B接口两次获取的数据都会是一样的。

mybatis打印sql日志分析

mybaits加载日志技术的顺序是:slf4j-->jcl--->log4j2--->log4j-->jul--->nolog
1.在spring4+mybatis+log4j的情况会有sql日志输出。

因为spring4使用的是jcl,jcl在引入log4j依赖下,就会使用了log4j技术打印sql日志。

2.在spring5+mybatis+log4j的情况不会有sql日志输出。

因为spring5使用的是spring-jcl(本质也是jcl),spring-jcl默认使用了jul(不再使用log4j而是用log4j2,在上面有详细说明)。
由于mybatis加载日志的顺序,jcl是先与log4j,所以该情况下导致了mybatis使用了jcl技术。

那么问题来了?为什么mybatis在使用jul的情况下,没有打印sql日志?

当使用了jul的时候,jul默认的日志级别是 INFO
原生的jdk的logging的日志级别是FINEST、FINE、INFO、WARNING、SEVERE分别对应我们常见的trace、debug、info、warn、error
  • 通过下图可以看到jdk14的isDebugEnabled()方法,是使用了Level.FINE,这个值是500
  • 在这里插入图片描述
  • 跟踪isLoggable()方法,可以看到下图,level.intValue()就是上面传递进去的Level.FINE是500,levelValue是800
  • 在这里插入图片描述
  • 这里跟踪一下levelValue的值,可以看到levelValue = Level.INFO.intValue() , INFO的值是800
  • 在这里插入图片描述
  • 在这里插入图片描述
  • 跟踪mybatis打印sql日志的源码,是判断了isDebugEnabled()返回的值,所以mybatis在使用jul的时候,是不能打印sql日志的。
  • 在这里插入图片描述
相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
2月前
|
Prometheus 监控 Java
日志收集和Spring 微服务监控的最佳实践
在微服务架构中,日志记录与监控对系统稳定性、问题排查和性能优化至关重要。本文介绍了在 Spring 微服务中实现高效日志记录与监控的最佳实践,涵盖日志级别选择、结构化日志、集中记录、服务ID跟踪、上下文信息添加、日志轮转,以及使用 Spring Boot Actuator、Micrometer、Prometheus、Grafana、ELK 堆栈等工具进行监控与可视化。通过这些方法,可提升系统的可观测性与运维效率。
286 1
日志收集和Spring 微服务监控的最佳实践
|
2月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
517 5
|
8月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
2091 1
|
9月前
|
负载均衡 Java API
Spring Cloud是什么及基本特性都有哪些?
Spring Cloud 是用于构建健壮云应用的框架,包含多个子项目。其核心组件如Eureka(服务注册与发现)、Hystrix(熔断器)、Ribbon(负载均衡)等,帮助开发者快速实现微服务架构。Spring Cloud 提供了服务注册与发现、分布式配置、路由、断路器等功能,简化了微服务开发与管理。本文将重点介绍服务注册与发现及分布式配置两大特性。
473 5
|
8月前
|
Java 微服务 Spring
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——使用Logger在项目中打印日志
本文介绍了如何在项目中使用Logger打印日志。通过SLF4J和Logback,可设置不同日志级别(如DEBUG、INFO、WARN、ERROR)并支持占位符输出动态信息。示例代码展示了日志在控制器中的应用,说明了日志配置对问题排查的重要性。附课程源码下载链接供实践参考。
985 0
|
8月前
|
SQL Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— application.yml 中对日志的配置
在 Spring Boot 项目中,`application.yml` 文件用于配置日志。通过 `logging.config` 指定日志配置文件(如 `logback.xml`),实现日志详细设置。`logging.level` 可定义包的日志输出级别,例如将 `com.itcodai.course03.dao` 包设为 `trace` 级别,便于开发时查看 SQL 操作。日志级别从高到低为 ERROR、WARN、INFO、DEBUG,生产环境建议调整为较高级别以减少日志量。本课程采用 yml 格式,因其层次清晰,但需注意格式要求。
780 0
|
8月前
|
Java API 开发者
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——slf4j 介绍
在软件开发中,`System.out.println()`常被用于打印信息,但大量使用会增加资源消耗。实际项目推荐使用slf4j结合logback输出日志,效率更高。Slf4j(Simple Logging Facade for Java)是一个日志门面,允许开发者通过统一方式记录日志,无需关心具体日志系统。它支持灵活切换日志实现(如log4j或logback),且具备简洁占位符和日志级别判断等优势。阿里巴巴《Java开发手册》强制要求使用slf4j,以保证日志处理方式的统一性和维护性。使用时只需通过`LoggerFactory`创建日志实例即可。
615 0
|
4月前
|
机器学习/深度学习 XML Java
【spring boot logback】日志logback格式解析
在 Spring Boot 中,Logback 是默认的日志框架,它支持灵活的日志格式配置。通过配置 logback.xml 文件,可以定义日志的输出格式、日志级别、日志文件路径等。
741 5
|
4月前
|
Java 数据库连接 API
Java 8 + 特性及 Spring Boot 与 Hibernate 等最新技术的实操内容详解
本内容涵盖Java 8+核心语法、Spring Boot与Hibernate实操,按考试考点分类整理,含技术详解与代码示例,助力掌握最新Java技术与应用。
148 2
|
10月前
|
监控 Java 应用服务中间件
SpringBoot是如何简化Spring开发的,以及SpringBoot的特性以及源码分析
Spring Boot 通过简化配置、自动配置和嵌入式服务器等特性,大大简化了 Spring 应用的开发过程。它通过提供一系列 `starter` 依赖和开箱即用的默认配置,使开发者能够更专注于业务逻辑而非繁琐的配置。Spring Boot 的自动配置机制和强大的 Actuator 功能进一步提升了开发效率和应用的可维护性。通过对其源码的分析,可以更深入地理解其内部工作机制,从而更好地利用其特性进行开发。
407 6

热门文章

最新文章