Java⽇志框架学习笔记

news2024/10/6 12:33:47

目录

1.⽇志概述

1.1 ⽇志是⽤来做什么的?

1.2 为什么要⽤到⽇志框架?

1.3 现有的⽇志框架有哪些?

1.4 ⽇志⻔⾯技术

2.logback

2.1 logback介绍

2.1.1 logback 模块

2.1.2 logback 组件

2.1.3 logback 配置

2.1.4 logback.xml 配置⽂件解析

2.2 SLF4j+logback进⾏⽇志管理

2.2.2 配置⽂件

2.2.3 代码实现

2.2.6 异步⽇志

2.2.7 ⾃定义Logger

2.2.8 配置⽂件转换器

2.2.9 logback-access模块

3.Log4j2

3.1.1Log4j2介绍

3.2.1 XML配置⽂件解析

3.2.2 Log4j2的使⽤

3.2.3 Log4j的Bug及解决⽅案

4.SpringBoot⽇志管理

4.1 SpringBoot⾃定义⽇志

4.1.1 SpringBoot默认的⽇志配置

4.1.2 使⽤logback-spring.xml⾃定义配置

4.1.3 多环境输出⽇志⽂件

4.2 SpringBoot整合Log4j2

5.demo源码:Java日志模板: Java日志信息,包括slf42,logback,springboot整合slf42


1.⽇志概述

1.1 ⽇志是⽤来做什么的?

⽇志⽂件是⽤于记录系统操作事件的⽂件集合,可分为 事件⽇志 消息⽇志 。具
有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作⽤。

1.2 为什么要⽤到⽇志框架?

因为软件系统发展到今天已经很复杂了,特别是服务器端软件,涉及到的知识,内
容,问题太多。在某些⽅⾯使⽤别⼈成熟的框架,就相当于让别⼈帮你完成⼀些基
础⼯作,你只需要集中精⼒完成系统的业务逻辑设计。⽽且框架⼀般是成熟,稳健
的,它可以处理系统很多细节问题,⽐如,事务处理,安全性,数据流控制等问
题。还有框架⼀般都经过很多⼈使⽤,所以结构很好,所以扩展性也很好,⽽且它
是不断升级的,你可以直接享受别⼈升级代码带来的好处。

1.3 现有的⽇志框架有哪些?

  • JULjava util logging
  • logback
  • log4j
  • log4j2
  • JCLJakarta Commons Logging
  • slf4j Simple Logging Facade for Java
⽇志框架出现的历史顺序:
log4j -->JUL-->JCL--> slf4j --> logback --> log4j2

1.4 ⽇志⻔⾯技术

当我们的系统变的更加复杂的时候,我们的⽇志就容易发⽣混乱。随着系统开发的 进⾏,可能会更新不同的⽇志框架,造成当前系统中存在不同的⽇志依赖,让我们 难以统⼀的管理和控制。就算我们强制要求所有的模块使⽤相同的⽇志框架,系统 中也难以避免使⽤其它类似spring  mybatis 等其它的第三⽅框架,它们依赖于我们规定不同的⽇志框架,⽽且它们⾃身的⽇志系统就有着不⼀致性,依然会出现⽇志体系的混乱。 所以我们需要借鉴JDBC的思想,为⽇志系统也提供⼀套⾯,那么我们就可以⾯ 向这些接⼝规范来开发,避免了直接依赖具体的⽇志框架。这样我们的系统在⽇志中,就存在了⽇志的⻔⾯和⽇志的实现。
1.4.1 ⽇志⻔⾯技术的优点
1. ⾯向接⼝开发,不再依赖具体的实现类。减少代码的耦合
2. 项⽬通过导⼊不同的⽇志实现类,可以灵活的切换⽇志框架
3. 统⼀ API ,⽅便开发者学习和使⽤
4. 统⼀配置便于项⽬⽇志的管理
1.4.2 ⽇志⻔⾯和⽇志实现的关系

⽤户可以使⽤⽇志⻔⾯,然后根据需求,动态的选择具体的⽇志实现框架。这样就
可以使所有⽇志实现框架拥有统⼀的规范。

2.logback

2.1 logback介绍

官⽹: http://logback.qos.ch
Logback 是由 log4j 创始⼈设计的另⼀个开源⽇志组件,性能⽐ log4j 要好。 log4j,
logback, slf4j 都出⾃于他之⼿。
SLF4j 绑定 Logback ⽆缝衔接,只需要⼀个 logback-classic-1.0.13.jar ,这个绑定包不
slf4j 项⽬提供的,⽽是是 logback 项⽬提供的,它本身就是基于 slf4j API 实现的。
logback 拥有以下优点:
  • 内核重写、测试充分、初始化内存加载更⼩,这⼀切让logback性能和log4j相⽐有诸多倍的提升
  • logback⾮常⾃然地直接实现了slf4j,这个严格来说算不上优点,只是这样,再理解slf4j的前提下会很容易理解logback,也同时很容易⽤其他⽇志框架替换 logback
  • logback有⽐较⻬全的200多⻚的⽂档
  • logback当配置⽂件修改了,⽀持⾃动重新加载配置⽂件,扫描过程快且安全, 它并不需要另外创建⼀个扫描线程
  • ⽀持⾃动去除旧的⽇志⽂件,可以控制已经产⽣⽇志⽂件的最⼤数量

2.1.1 logback 模块

logback-core: 其他两个模块的基础模块
logback-class :它是 log4j 的改良版本,完整实现了 Slf4j API
logback-access: 访问模块与 servlet 容器继承提供通过 Http 来访问⽇志的功能

2.1.2 logback 组件

1 Logger: ⽇志的记录器,把它关联到应⽤的对应的 context 上后,主要⽤于存放⽇志对象,也可以定义⽇志类型、级别。
2 Appender: ⽤于指定⽇志输出的⽬的地,可以是控制台、⽂件、数据库等等。
3 Layout: 负责把事件转换成字符串,格式化的⽇志信息的输出。在 logback 中Layout对象被封装在 encoder 中。

2.1.3 logback 配置

logback 会依次读取以下类型配置⽂件 :
1 logback.grovy
2 logback-test.xml
3 logback.xml

2.1.4 logback.xml 配置⽂件解析

<?xml version="1.0" encoding="UTF-8" ?>

<configuration>

    <!-- 定义配置属性,可以直接使用该属性的值,格式:${name} -->
    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"/>
    <property name="log_dir" value="G://logs"/>
    <!-- 控制台日志输出的Appender -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <target>System.out</target> <!--System.err  区别就是颜色不同-->
        <!--日志消息格式设置 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>


    <!-- 输出文件Appender -->
    <appender name="file" class="ch.qos.logback.core.FileAppender">
        <file>${log_dir}/logback.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>


    <!-- html格式日志文件输出Appender -->
    <appender name="html" class="ch.qos.logback.core.FileAppender">
        <file>${log_dir}/logback.html</file>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <pattern>%-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c %M %L %thread %m</pattern>
            </layout>
        </encoder>
    </appender>

    <!-- 日志拆分和归档压缩的Appender -->
    <appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志文件保存的路径 -->
        <file>${log_dir}/roll_logback.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- 拆分规则 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 按照时间和压缩格式声明拆分的文件名 -->
            <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd-HH-ss}.log%i.gz</fileNamePattern>
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
    </appender>


    <!-- 日志级别过滤器 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>ERROR</level>
        <onMatch>ACCEPT</onMatch>
        <omMismatch>DENY</omMismatch>
    </filter>


    <!-- 异步日志 -->
    <appender name="asyncInfo" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 默认不丢失日志,如果队列的80%已满,则会丢失TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 默认256 队列大小 -->
        <queueSize>256</queueSize>
        <!-- 绑定异步的appender只能添加一个 -->
        <appender-ref ref="rollFile"/>
    </appender>


    <root level="ALL">
        <appender-ref ref="console"/>
        <appender-ref ref="rollFile"/>
        <appender-ref ref="file"/>
        <appender-ref ref="html"/>
    </root>
</configuration>
⽇志输出格式:
%-5level
%d{yyyy-MM-dd HH:mm:ss.SSS}⽇期
%c类的完整名称
%M为method
%L为⾏号
%thread线程名称
%m或者%msg为信息
%n换⾏
格式化输出:
%d表示⽇期,
%thread表示线程名,
%-5level:级别从左显示5个字符宽度
%msg:⽇志消息
%n是换⾏符

2.2 SLF4j+logback进⾏⽇志管理

SLF4j 绑定 Logback ,只需要⼀个 logback-classic-1.0.13.jar
2.2.1 导包
<dependencies>
<!-- slf4j ⽇志⻔⾯ -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<!-- logback ⽇志实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>

2.2.2 配置⽂件

log4j2.xml
<?xml version="1.0" encoding="UTF-8" ?>

<configuration>

    <!-- 定义配置属性,可以直接使用该属性的值,格式:${name} -->
    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"/>
    <property name="log_dir" value="G://logs"/>
    <!-- 控制台日志输出的Appender -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <target>System.out</target> <!--System.err  区别就是颜色不同-->
        <!--日志消息格式设置 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>


    <!-- 输出文件Appender -->
    <appender name="file" class="ch.qos.logback.core.FileAppender">
        <file>${log_dir}/logback.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>


    <!-- html格式日志文件输出Appender -->
    <appender name="html" class="ch.qos.logback.core.FileAppender">
        <file>${log_dir}/logback.html</file>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <pattern>%-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c %M %L %thread %m</pattern>
            </layout>
        </encoder>
    </appender>

    <!-- 日志拆分和归档压缩的Appender -->
    <appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志文件保存的路径 -->
        <file>${log_dir}/roll_logback.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- 拆分规则 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 按照时间和压缩格式声明拆分的文件名 -->
            <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd-HH-ss}.log%i.gz</fileNamePattern>
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
    </appender>


    <!-- 日志级别过滤器 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>ERROR</level>
        <onMatch>ACCEPT</onMatch>
        <omMismatch>DENY</omMismatch>
    </filter>


    <!-- 异步日志 -->
    <appender name="asyncInfo" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 默认不丢失日志,如果队列的80%已满,则会丢失TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 默认256 队列大小 -->
        <queueSize>256</queueSize>
        <!-- 绑定异步的appender只能添加一个 -->
        <appender-ref ref="rollFile"/>
    </appender>


    <root level="ALL">
        <appender-ref ref="console"/>
        <appender-ref ref="rollFile"/>
        <appender-ref ref="file"/>
        <appender-ref ref="html"/>
    </root>
</configuration>

2.2.3 代码实现

package com.wang;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.stream.IntStream;

/**
 * @author 飞
 */
public class Test {
    public static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
    public static void main(String[] args) {
        IntStream.range(0, 10000).forEach(i -> {
            LOGGER.trace("trace");
            LOGGER.debug("debug"); // 默认输出级别
            LOGGER.info("info");
            LOGGER.warn("warn");
            LOGGER.error("error");
        });
    }

}
2.2.4 ⽇志拆分
所有信息都输出到同⼀个⽇志⽂件,⽇志的产⽣速度很快,⽂件⼀⼤,就很难分析,因此需要进⾏拆分。
    <!-- 日志拆分和归档压缩的Appender -->
    <appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志文件保存的路径 -->
        <file>${log_dir}/roll_logback.log</file>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!-- 拆分规则 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 按照时间和压缩格式声明拆分的文件名 -->
            <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd-HH-ss}.log%i.gz</fileNamePattern>
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
    </appender>
2.2.5 过滤器
<!-- 日志级别过滤器 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>ERROR</level>
    <onMatch>ACCEPT</onMatch>
    <omMismatch>DENY</omMismatch>
</filter>
该过滤器表示:⼤于等于 error 级别的⽇志才会被输出到⽂件中

2.2.6 异步⽇志

为了提升性能,应该将⽇志设置为异步,同步⽇志意味着⽇志必须完成才能执⾏后续代码,但是⽇志毕竟是 io 操作,会影响程序速度配置异步⽇志很简单,新增⼀个 appender ,指定其为 async, 并调⽤现有的 appender 即可。
    <!-- 异步日志 -->
    <appender name="asyncInfo" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 默认不丢失日志,如果队列的80%已满,则会丢失TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 默认256 队列大小 -->
        <queueSize>256</queueSize>
        <!-- 绑定异步的appender只能添加一个 -->
        <appender-ref ref="rollFile"/>
    </appender>

2.2.7 ⾃定义Logger

我们可以针对⾃⼰的业务代码⾃定义 logger 对象,可以不必继承 rootLogger
<!--⾃定义logger对象 additivity属性表示⾃定义logger对象是否继承rootLogger
 在 com.wang包下的类⽇志都使⽤此logger对象-->
<logger name="com.wang" level="info" additivity="false">
 <appender-ref ref="console" />
</logger>

2.2.8 配置⽂件转换器

http://logback.qos.ch/translator/ 可以将 log4j 的配置转成 logback 的配置格式

2.2.9 logback-access模块

logback-access 模块与 Servlet 容器 ( Tomcat Jetty) 集成,以提供 HTTP 访问⽇志功能。我们可以使⽤logback-access 模块来替换 tomcat 的访问⽇志。
具体参考官⽹⽂档 https://logback.qos.ch/access.h

3.Log4j2

3.1.1Log4j2介绍

Log4j2 是对 Log4j 的升级版本, 015 5 ⽉, Apache 宣布 log4j1.x 停⽌更新。
Log4j Log4j2 下载地址: https://logging.apache.org/
log4j2 参考了 logback 的⼀些优秀的设计,并且修复了⼀些问题,因此带来了⼀些重⼤的提升,主要有:
1 、异常处理:在 logback 中, Appender 中的异常不会被应⽤感知到,但是在 log4j2中,提供了⼀些异常处理机制。
2 、性能提升: log4j2 相较于 log4j 1 logback 都具有很明显的性能提升。
3 、⾃动重载配置:参考了 logback 的设计,提供⾃动刷新参数配置,可以动态的修改⽇志的级别⽽不需要重启应⽤。
4 、⽆垃圾机制, log4j2 在⼤部分情况下,都可以使⽤其设计的⼀套⽆垃圾机制,避免频繁的⽇志收集导致的jvm gc
log4j 2.x 版本不再⽀持像 1.x 中的 .properties 后缀的⽂件配置⽅式, 2.x 版本配置⽂件
后缀名只能为 ".xml",".json" 或者 ".jsn"
log4j2 虽然采⽤ xml ⻛格进⾏配置,依然包含三个组件分别是 Loggers (记录器)、
Appender (输出⽬的地)、 Layout (⽇志布局)。
配置⽂件的位置: log4j2 默认会在 classpath ⽬录下寻找 log4j2.xml log4j.json 、log4j.jsn等名称的⽂件。

3.2.1 XML配置⽂件解析

1 、根节点 Configuration 有两个属性 :status monitorinterval, 有两个⼦节点:Appenders Loggers( 表明可以定义多个 Appender Logger
status ⽤来指定 log4j 本身的打印⽇志的级别
monitorinterval log4j 2.x 新特点⾃动重载配置。指定⾃动重新配置的监测间隔时
间,单位是 s, 最⼩是 5s
2 Appenders 节点,常⻅的有三种⼦节点 :Console File RollingFile
Console 节点⽤来定义输出到控制台的 Appender
File 节点⽤来定义输出到指定位置的⽂件的 Appender
RollingFile 节点⽤来定义超过指定⼤⼩⾃动删除旧的创建新的的 Appender
通过在⼦节点中加⼊进⾏⽇志布局:
%p : 输出⽇志信息优先级,即 DEBUG INFO WARN ERROR FATAL,
%d : 输出⽇志时间点的⽇期或时间,默认格式为 ISO8601 ,也可以在其后指定格式,⽐如:%d{yyy MMM dd HH : mm : ss,SSS} ,输出类似: 2002 10 18 22 10 28 ,921
%r : 输出⾃应⽤启动到输出该 log 信息耗费的毫秒数
%c : 输出⽇志信息所属的类⽬,通常就是所在类的全名
%t : 输出产⽣该⽇志事件的线程名
%l : 输出⽇志事件的发⽣位置,相当于 %C.%M(%F : %L) 的组合 , 包括类⽬名、发⽣的线
程,以及在代码中的⾏数。举例: Testlog4.main(TestLog4.Java : 10)
%x : 输出和当前线程相关联的 NDC( 嵌套诊断环境 ), 尤其⽤到像 Java servlets 这样的多客户多线程的应⽤中。
%% : 输出⼀个 ”%” 字符
%F : 输出⽇志消息产⽣时所在的⽂件名称
%L : 输出代码中的⾏号
%m : 输出代码中指定的消息 , 产⽣的⽇志具体信息
%n : 输出⼀个回⻋换⾏符, Windows 平台为 ”\r\n” Unix 平台为 ”\n” 输出⽇志信息换⾏
3 Loggers 节点,常⻅的有两种: Root Logger
Root 节点⽤来指定项⽬的根⽇志,如果没有单独指定 Logger ,那么就会默认使⽤该Root⽇志输出
Logger 节点⽤来单独指定⽇志的形式,⽐如要为指定包下的 class 指定不同的⽇志级别等。

3.2.2 Log4j2的使⽤

1 导包
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-api</artifactId> <!-- ⽇志⻔⾯ -->
 <version>2.19</version>
</dependency>
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-core</artifactId><!-- ⽇志实现 -->
 <version>2.19</version>
</dependency>
2 创建配置⽂件
<?xml version="1.0" encoding="UTF-8" ?>
<configuration status="error">
    <!--定义所有的appender -->
    <appenders>
        <Console name="console" target="SYSTEM_OUT">
            <!--控制台日志级别为trace以上的信息(ACCEPT) 其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level = "trace" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern = "%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %m%n"/>
        </Console>

        <File name="log" fileName="G:/logs/log4j2.log" append = "true">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %m%n"/>
        </File>

        <File name="error" fileName="G:/logs/log4j2_error.log">
            <ThresholdFilter level = "error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern = "%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %m%n"/>
        </File>

        <!--打印出所有消息,每次大小超过size,则size大小的日志会自定存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
        <RollingFile name="rollingFile" fileName="G:/logs/web.log"
                     filePattern="logs/$${date:yyyy-MM}/web-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern = "%d{yyyy.MM.dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %m%n"/>
            <SizeBasedTriggeringPolicy size="2MB"/>
        </RollingFile>

    </appenders>

    <loggers>
        <root level = "trace">
            <appender-ref ref="rollingFile"/>
            <appender-ref ref="console"/>
            <appender-ref ref="error"/>
            <appender-ref ref="log"/>
        </root>
    </loggers>

</configuration>


3 应⽤
package com.wang;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Test {

    private static Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);

    public static void main(String[] args) {

        for (int i= 0;i<3;i++){
            // 记录trace级别的日志信息
            logger.trace("log4j日志输出:This is trace message.");
            // 记录debug级别的日志信息
            logger.debug("log4j日志输出:This is debug message.");
            // 记录info级别的日志信息
            logger.info("log4j日志输出:This is info message.");
            // 记录error级别的日志信息
            logger.error("log4j日志输出:This is error message.");
        }


    }

}

3.2.3 Log4jBug及解决⽅案

解决⽅式
  • 禁⽤lookupJNDI服务
罪魁祸⾸就是lookup JNDI ,那么直接修改配置⽂件 log4j2.formatMsgNoLookups=True或禁⽤ JNDI 服务,不过⼀般产⽣问题的服务都是线上已经在跑的服务,禁⽤的时候要注意评估⼀下是否允许。
  • 升级Apache Log4j
这次产⽣的影响范围主要是在 Apache Log4j 2.x <= 2.14.1 ,所以直接把 Log4j 升级即可解决。

4.SpringBoot⽇志管理

4.1 SpringBoot⾃定义⽇志

SpringBoot 内部使⽤ logback 作为系统⽇志实现的框架,将⽇志输出到控制台,不会写到⽇志⽂件。如果在application.properties application.yml 配置,这样只能配置简单的场景,保存路径、⽇志格式等。复杂的场景(区分 info error 的⽇志、每天产⽣⼀个⽇志⽂件等)满⾜不了,只能⾃定义配置⽂件logback-spring.xml

4.1.1 SpringBoot默认的⽇志配置

格式说明
时间戳 , 精确到毫秒 : 2022-10-27 12:38:39.195
logback ⽇志级别 . ⽇志级别分为: TRACE DEBUG INFO WARN ERROR
FATAL: INFO
进程 ID: 16816
分割符 : 默认是 : ---
线程名称 : [main]
SpringBoot 从控制台打印出来的⽇志级别默认只有 INFO 及以上级别,可以在application.properties中修改⽇志级别 logging.level.root=WARN
application.properties 配置⽂件中添加:
logging.level.root = WARN
<dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <version>1.18.12</version>
</dependency>
package com.wang.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.stream.IntStream;

/**
 * @author 飞
 */
@Slf4j //lombok 提供的注解
@RestController
@RequestMapping("log")
public class LogController {
    //如果不使⽤lombok就需要⽤以下代码获取⽇志操作对象
    //Logger log = LoggerFactory.getLogger(LogController.class);
    @GetMapping("/test")
    public String test(){
        IntStream.range(0, 1000).forEach(i -> {
            log.trace("hello trace");
            log.debug("hello debug");
            log.info("hello info");
            log.warn("hello warn");
        });
        return "SpringBoot日志管理";
    }

}
root 是项⽬所有的⽇志级别。启动成功了,但是没有⽇志输出。我们把默认的⽇志级别设置成WARN, 按照层级关系 INFO,DEBUG,TRACE 的⽇志都不输出。我们在 application.properties root 的⽇志级别改成 INFO ,⾃⼰的写的业务包⽇志级别改成DEBUG
logging.level.root=INFO //root⽇志以INFO级别输出信息
logging.level.com.wang.controller.config=WARN //指定config包下的类以WARN级别输出
运⾏之后, log.info(" 这是 info 级别⽇志 ") 没有输出。
⽇志的其它配置项
logging.config ⽇志配置;
logging.logback.rollingpolicy.max-file-size ( 低版本⽤ logging.file.max-size ) 最⼤⽇志⽂件⼤⼩;
logging.logback.rollingpolicy.max-history ( 低版本 logging.file.max-history ) 最⼤归档⽂件数量;
logging.pattern.console 控制台输出的⽇志模式;
logging.pattern.dateformat ⽇志的⽇期格式;
logging.pattern.file 默认使⽤⽇志模式
logging.pattern.level ⽇志级别
logging.config ⽇志配置;
logging.logback.rollingpolicy.max-file-size ( 低版本⽤ logging.file.max-size ) 最⼤⽇志⽂件⼤⼩;
logging.logback.rollingpolicy.max-history ( 低版本 logging.file.max-history ) 最⼤归档⽂件数量;
logging.pattern.console 控制台输出的⽇志模式;
logging.pattern.dateformat ⽇志的⽇期格式;
logging.pattern.file 默认使⽤⽇志模式
logging.pattern.level ⽇志级别

4.1.2 使⽤logback-spring.xml⾃定义配置

⽇志服务⼀般都在 ApplicationContext 创建前就初始化了,它并不是必须通过 Spring的配置⽂件控制。因此通过系统属性和传统的Spring Boot 外部配置⽂件依然可以很好的⽀持⽇志控制和管理。在类路径下放置⾃定义⽇志配置xml ⽂件, SpringBoot就不会使⽤它本身的默认⽇志配置了。下图是SpringBoot 官⽅⽂档的提示内容,意思是:根据您的⽇志记录系统,将加载相应的⽂件使⽤。即如果我们使⽤logback ⽇志框架,那么可以使⽤ logback-spring.xml、 logback-spring.groovy logback.xml logback.groovy 之⼀作为配置⽂件来加载。根据不同的⽇志系统,你可以按如下规则组织配置⽂件名,并且放在src/main/resources下⾯就能被正确加载:
Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
Log4j2:log4j2-spring.xml, log4j2.xml
JDK (Java Util Logging):logging.properties
logback-spring.xml 的配置模板:
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
 <!-- 定义配置属性,可以直接使⽤该属性的值,格式:${name} -->
 <property name="pattern" value="[%-5level] %d{yyyy-MM-dd
HH:mm:ss.SSS} %c %M %L [%thread] %m%n"/>
 <property name="log_dir" value="C://logs"/>
 <!-- 控制台⽇志输出的Appender -->
 <appender name="console"
class="ch.qos.logback.core.ConsoleAppender">
 <target>System.out</target> <!--System.err 区别就是颜⾊不
同-->
 <!--⽇志消息格式设置 -->
 <encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
 <pattern>${pattern}</pattern>
 </encoder>
 </appender>
 <!-- 输出⽂件Appender -->
 <appender name="file"
class="ch.qos.logback.core.FileAppender">
 <file>${log_dir}/logback.log</file>
 <encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
 <pattern>${pattern}</pattern>
 </encoder>
 </appender>
<!-- html格式⽇志⽂件输出Appender -->
 <appender name="html"
class="ch.qos.logback.core.FileAppender">
 <file>${log_dir}/logback.html</file>
 <encoder
class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
 <layout
class="ch.qos.logback.classic.html.HTMLLayout">
 <pattern>%-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c %M
%L %thread %m</pattern>
 </layout>
 </encoder>
 </appender>
 <!-- ⽇志拆分和归档压缩的Appender -->
 <appender name="rollFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
 <!-- ⽇志⽂件保存的路径 -->
 <file>${log_dir}/roll_logback.log</file>
 <encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
 <pattern>${pattern}</pattern>
 </encoder>
 <!-- 拆分规则 -->
 <rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
 <!-- 按照时间和压缩格式声明拆分的⽂件名 -->
 <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd-HHss}.log%i.gz</fileNamePattern>
 <maxFileSize>1MB</maxFileSize>
 </rollingPolicy>
 </appender>
 <!-- ⽇志级别过滤器 -->
 <filter class="ch.qos.logback.classic.filter.LevelFilter">
 <level>ERROR</level>
 <onMatch>ACCEPT</onMatch>
<omMismatch>DENY</omMismatch>
 </filter>
 <!-- 异步⽇志 -->
 <appender name="asyncInfo"
class="ch.qos.logback.classic.AsyncAppender">
 <!-- 默认不丢失⽇志,如果队列的80%已满,则会丢失TRACT、DEBUG、
INFO级别的⽇志 -->
 <discardingThreshold>0</discardingThreshold>
 <!-- 默认256 队列⼤⼩ -->
 <queueSize>256</queueSize>
 <!-- 绑定异步的appender只能添加⼀个 -->
 <appender-ref ref="rollFile"/>
 </appender>
 <root level="ALL">
 <appender-ref ref="console"/>
 <appender-ref ref="rollFile"/>
 <appender-ref ref="asyncInfo"/>
<!-- <appender-ref ref="file"/>-->
<!-- <appender-ref ref="html"/>-->
 </root>
</configuration>

4.1.3 多环境输出⽇志⽂件

SpringBoot 官⽅建议使⽤ logback-spring.xml 作为 logback 框架的⾃定义⽇志配置⽂件,使⽤logback-spring.xml ⽽不是 logback.xml ,因为带 -spring 后缀的配置⽂件可以使⽤使⽤Spring 扩展 profile ⽀持,提供 profile 多环境⽇志输出得功能。
Logback 配置⽂件中的 节点指令允许您根据配置⽂件激活参数 (active) 选择性的包含和排查部分配置信息。根据不同环境来定义不同的⽇志输出,在 logback-spring.xml中使⽤ 节点来定义,⽅法如下:
<!--开发环境:打印控制台-->
<springProfile name="dev">
 <!--⽤来设置某⼀个包或者具体的某⼀个类的⽇志打印级别,可以让控制台输出debug addtivity="false"不向上传递-->
 <logger name="com.laoxue.contoller.test" level="debug"
addtivity="false"/>
 <!--root节点是必选节点,⽤来指定最基础的⽇志输出级别,只有⼀个level属性,可以包含零个或多个appender元素-->
 <root level="INFO">
 <appender-ref ref="console" />
 </root>

 </springProfile>
 <!--⽣产环境:输出到⽂件-->
 <springProfile name="pro">
 <root level="INFO">
 <appender-ref ref="rollFile"/>
 <appender-ref ref="asyncInfo"/>
 </root>


 </springProfile>
以启动服务的时候指定 profile (如不指定使⽤默认),如指定 prod 的⽅式为:
java -jar xxx.jar –spring.profiles.active=prod

4.2 SpringBoot整合Log4j2

Apache Log4j 2 Log4j1. x 的升级版,⽐它的祖先 Log4j 有了很⼤的改进,和 logback对⽐有很⼤的改进。除了内部设计的调整外,主要有以下⼏点的⼤升级:
  • 更简化的配置
  • 更强⼤的参数格式化
  • 强⼤的异步性能
Log4j 2 中,分为 API(log4j-api )和实现 (log4j-core) 两个模块。 API slf4j 是⼀个类
型,属于⽇志抽象 / ⻔⾯,⽽实现部分,才是 Log4j 2 的核⼼。
  • org.apache.logging.log4j » log4j-api
  • org.apache.logging.log4j » log4j-core
相⽐与其他的⽇志系统, log4j2 丢数据这种情况少; disruptor 技术,在多线程环境下,性能⾼于logback 10 倍以上;利⽤ jdk1.5 并发的特性,减少了死锁的发⽣;同步⽇志模式下, Logback 的性能是最糟糕的, log4j2 的性能⽆论在同步⽇志模式还是异步⽇志模式下都是最佳的。

1.pom配置

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <!-- 去掉springboot默认配置 -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
            <version>2.7.5</version>
        </dependency>

        <!-- 引入log4j2的配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>

    </dependencies>

2. 配置⽂件

默认名 log4j2-spring.xml. 如果是其它的名字需要在配置⽂件中指定
logging.config=xxx.xml
配置⽂件模板:
<?xml version="1.0" encoding="UTF-8"?>
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration monitorInterval="5">
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->

    <!--变量配置-->
    <Properties>
        <!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
        <!-- %logger{36} 表示 Logger 名字最长36个字符 -->
        <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
        <!-- 定义日志存储的路径 -->
        <property name="FILE_PATH" value="G://logs" />
        <property name="FILE_NAME" value="springboot-log" />
    </Properties>

    <appenders>

        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
        </console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
        <File name="File-log" fileName="${FILE_PATH}/test.log" append="false">
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </File>

        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="1MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

        <!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="1MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

        <!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="1MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

    </appenders>

    <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
    <!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.mybatis" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </logger>
        <!--监控系统信息-->
        <!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
        <Logger name="org.springframework" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <root level="info"> <!--定义日志级别,大于等于info级别的日志都将被输出-->
            <appender-ref ref="Console"/>
            <appender-ref ref="File-log"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
        </root>

    </loggers>

</configuration>

5.demo源码:Java日志模板: Java日志信息,包括slf42,logback,springboot整合slf42

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/194692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023网络爬虫 -- 获取动态数据

一、网站的正常界面1、网址https://movie.douban.com/typerank?type_name%E5%8A%A8%E4%BD%9C%E7%89%87&type5&interval_id100:90&action2、正常的页面二、爬取数据1、源代码import requests头{"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64…

首屏加载速度慢怎么解决?

一、什么是首屏加载 首屏时间&#xff08;First Contentful Paint&#xff09;&#xff0c;指的是浏览器从响应用户输入网址地址&#xff0c;到首屏内容渲染完成的时间&#xff0c;此时整个网页不一定要全部渲染完成&#xff0c;但需要展示当前视窗需要的内容 首屏加载可以说是…

分享156个ASP源码,总有一款适合您

ASP源码 分享156个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 156个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1Mc-zWjUyk9Lx8TXv5cvZTg?pwds2qi 提取码&#x…

Office 365用户登录审核

黑客访问端点设备&#xff0c;以窃取公司特定数据、员工个人数据或任何其他可能对他们有任何用处的有价值的信息。 为了帮助您防止这种攻击&#xff0c;我们编写了一个参数列表&#xff0c;可以帮助您识别异常日志&#xff0c;这通常是攻击的第一个标志。异常登录活动是安全漏洞…

Vue使用ElementUI的确认框进行删除操作(包含前后端代码)

前言 今天做自己项目的时候&#xff0c;有一个删除的业务&#xff0c;正好遇到了确认框&#xff0c;在此纪念一下。 这里我是使用的ElementUI的确认框&#xff01; 首先ElementUI的确认框是这么说明的&#xff1a; 从场景上说&#xff0c;MessageBox 的作用是美化系统自带的 …

Java程序员跳槽,三面全过,面试官:你这样的,我们招不起

程序员小李在沿海城市工作了8年&#xff0c;那里涨幅飞快的房价限制了程序员小李在一线城市安家的想法&#xff0c;再加上突然发生的疫情暴露了远在他乡工作的不便&#xff0c;在种种因素下&#xff0c;程序员小李决定回家工作。 既然已经下定决心告别一线城市回家乡发展&…

数据分析面试-sql练习

SQL汇总1. SQL执行顺序2. 开窗函数3. 经典SQL题3.0 数据准备3.1 ☆ 查询‘01’课程比‘02’课程成绩高的学生3.2 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩3.3 查询在SC表存在成绩的学生信息3.4 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总…

Github每日精选(第96期):微软的机器学习课程ML-For-Beginners

12 周&#xff0c;26 节课&#xff0c;52 道测验&#xff0c;适合所有人的经典机器学习。 添加链接描述 初学者机器学习 - 课程 Microsoft 的 Azure Cloud Advocates 很高兴提供为期 12 周、26 节课的全部关于机器学习的课程。在本课程中&#xff0c;您将了解有时称为经典机器…

【C++】面向对象:继承

&#x1f431;作者&#xff1a;傻响 &#x1f431;专栏&#xff1a;《C语法》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 C中的继承 1.继承的概念及定义 1.1继承的概念 1.2 继承定义 1.3 继承关系和访问限定符 1.4 继承基类成…

ES6中扩展运算符的9种用法

1. 拷贝数组对象 const years [2018, 2019, 2020, 2021]; const copyYears [...years];console.log(copyYears); // [ 2018, 2019, 2020, 2021 ]扩展运算符拷贝数组&#xff0c;只有第一层是深拷贝&#xff0c;即对一维数组使用扩展运算符拷贝就属于深拷贝 2. 合并数组 先…

c++入门语法

文章目录1. 命名空间1.1 域的介绍1.2 命名空间的定义1.3 命名空间的三种使用方式2. C输入&&输出3. 缺省参数3.1 概念3.2 缺省参数分类4. 函数重载4.1 概念4.2 C支持函数重载的原理--名字修饰5. 引用5.1 概念5.2 特性5.3 常引用5.4 使用场景5.5 指针和引用的区别6. 内联…

OpenCV-PyQT项目实战(3)信号与槽机制

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列&#xff0c;持续更新中 OpenCV-PyQT项目实战&#xff08;1&#xff09;安装与环境配置 OpenCV-PyQT项目实战&#xff08;2&#xff09;QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战&#xff08;3&#xff09;信号与槽机制 …

健身大神都戴什么耳机、健身大佬的耳机清单分享

平时&#xff0c;我们总能看到许多运动健身的人群&#xff0c;在锻炼时都佩戴着耳机。但运动耳机的选择&#xff0c;同样是大有学问的。如果佩戴传统的真无线蓝牙耳机&#xff0c;有可能出现佩戴不稳、耳道肿胀等问题&#xff0c;影响运动体验。所以今天我们特意给大家带来几款…

【大数据实时数据同步】OGG异构多路映射同步原表审计表只存删除数据表实现方案(二)

文章目录前言十一、将SCOTT下所有已同步的HIS表逻辑同步配置改为DEL表操作1、首先来看一下抽取进程和应用进程我们要修改成什么样的配置2、开始前先停止源端的抽取进程3、清除原来HIS表非DELETE操作数据4、启动抽取进程和应用进程验证总结前言 这里是后续&#xff01;&#xf…

尚医通 (一)项目介绍

目录一、功能简介二、技术点三、业务流程四、系统架构一、功能简介 尚医通即为网上预约挂号系统&#xff0c;网上预约挂号是近年来开展的一项便民就医服务&#xff0c;旨在缓解看病难、挂号难的就医难题&#xff0c;许多患者为看一次病要跑很多次医院&#xff0c;最终还不一定…

微信小程序 python垃圾分类知识科普系统 uniapp

目 录 摘 要 III Abstract 4 1 系统概述 5 1.1 概述 5 1.2课题意义 5 1.3 主要内容 5 2 系统开发环境 6 2.1微信开发者工具 6 2.2小程序框架以及目录结构介绍 6 3 需求分析 1 3.1 系统设计目标 1 3.2需求分析概述 1 3.3 系统可行性分析…

分享160个ASP源码,总有一款适合您

分享160个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 160个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1xMcHd2x-EW0PP4TdVCU5vA?pwd3hby 提取码&#xff1a;3hby…

嵌入式开发:如何在嵌入式市场中平衡敏捷

敏捷方法的好处是有据可查的&#xff0c;但是在遵从驱动的市场中&#xff0c;向敏捷过渡对于嵌入式开发团队来说是一个挑战。需要可追溯性和文档来证明遵从性&#xff0c;但是这可能与敏捷的精神相矛盾&#xff0c;敏捷的精神仍然受到伴随着方法论成长起来的不准确神话的困扰。…

创建者模式—原型模式(深克隆和浅克隆的区别)

目录 1.原型模式 1.1概念 1.2结构 1.3实现 1.4案例 1.5深克隆&#xff08;扩展&#xff09; 2.浅克隆和深克隆 2.1克隆的特点 2.2浅克隆和深克隆的区别 1.原型模式 1.1概念 用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对…

【分布式任务调度】XXL-JOB快速搭建教程

XXL-JOB1. XXL-JOB简介2. XXL-JOB搭建2.1 准备工作2.1.1 下载源码2.1.2 数据库准备 数据库脚本在doc路径下&#xff0c;将其执行之后可以创建一个数据库&#xff0c;如图3所示&#xff1a;2.2 搭建调度中心2.3 搭建“执行器”3. 测试3.1 新增执行器3.2 新增任务3.3 启动任务测试…