SLF4J的介绍与使用(有logback和log4j2的具体实现案例)

news2024/9/9 0:46:05

目录

1.日志门面的介绍

常见的日志门面 :

常见的日志实现:

日志门面和日志实现的关系:

2.SLF4J 的介绍

业务场景(问题):

SLF4J的作用

SLF4J 的基本介绍

 日志框架的绑定(重点)

桥接旧的日志框架

SLF4J原理解析

3.SLF4J 的使用

非Springboot项目

 Springboot项目(重点)

Springboot中使用logback

Springboot中使用log4j2


1.日志门面的介绍

当我们的系统变的更加复杂的时候,我们的日志就容易发生混乱。随着系统开发的进行,可能会更新不同的日志框架,造成当前系统中存在不同的日志依赖,让我们难以统一的管理和控制。就算我们强制要 求所有的模块使用相同的日志框架,系统中也难以避免使用其他类似spring,mybatis等其他的第三方框 架,它们依赖于我们规定不同的日志框架,而且他们自身的日志系统就有着不一致性,依然会出来日志 体系的混乱。

所以我们需要借鉴JDBC的思想,为日志系统也提供一套门面,那么我们就可以面向这些接口规范来开 发,避免了直接依赖具体的日志框架。这样我们的系统在日志中,就存在了日志的门面和日志的实现。

常见的日志门面 :

JCL、slf4j

常见的日志实现:

JUL、log4j、logback、log4j2

日志门面和日志实现的关系:

通过这关系图,就大概知道了其实日志门面就类似于一套标准的接口,然后不同的日志实现框架基于这套标准的接口去实现具体的功能。 

简单来说,它仅仅是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案,就比如JDBC一样,只是一种规则而已。所以单独的slf4j是不能工作的,必须搭配其他具体的日志实现方案

日志框架出现的历史顺序:

log4j -->JUL-->JCL--> slf4j --> logback --> log4j2

2.SLF4J 的介绍

业务场景(问题):

现在开发项目都是使用maven进行构建开发,假设架构师a开发了一个通用组件A,他在程序中使用的是log4j组件进行日志输出;程序员b自己之前一直在开发自己的业务模块,并且他在程序中使用的是logback日志组件,突然有一天程序员b需要在自己的业务系统中使用架构师a的通用组件A,这个时候问题就出现了,由于两套程序使用了不同的日志组件,程序员b除了要维护自己的logback日志组件配置,还需要维护通用组件A的日志配置,如何让他们的日志输出整合到一起,这个问题是很头疼的。这时候,使用slf4j就可以完美解决问题

SLF4J的作用

* 1. 使用SLF4J框架,可以在部署时迁移到所需的日志记录框架。

* 2. SLF4J提供了对所有流行的日志框架的绑定,例如log4j,JUL,Simple logging和NOP。因此可以 在部署时切换到任何这些流行的框架。

* 3. 无论使用哪种绑定,SLF4J都支持参数化日志记录消息。由于SLF4J将应用程序和日志记录框架分离, 因此可以轻松编写独立于日志记录框架的应用程序。而无需担心用于编写应用程序的日志记录框架。

* 4. SLF4J提供了一个简单的Java工具,称为迁移器。使用此工具,可以迁移现有项目,这些项目使用日志 框架(如Jakarta Commons Logging(JCL)或log4j或Java.util.logging(JUL))到SLF4J。

SLF4J 的基本介绍

简单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Java日志访问提供一套标准、规范 的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j和logback等。 当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。对于一般的Java项目而言,日志框架 会选择slf4j-api作为门面,配上具体的实现框架(log4j、logback等),中间使用桥接器完成桥接。

官方网站: https://www.slf4j.org/

SLF4J是目前市面上最流行的日志门面。现在的项目中,基本上都是使用SLF4J作为我们的日志系统。

SLF4J日志门面主要提供两大功能:

1. 日志框架的绑定

2. 日志框架的桥接

 日志框架的绑定(重点)

如前所述,SLF4J支持各种日志框架。SLF4J发行版附带了几个称为“SLF4J绑定”的jar文件,每个绑定对应 一个受支持的框架。

 要切换日志框架,只需替换类路径上的slf4j绑定。例如,要从java.util.logging切换到log4j,只需将 slf4j-jdk14-1.7.27.jar替换为slf4j-log4j12-1.7.27.jar即可。

SLF4J不依赖于任何特殊的类装载。实际上,每个SLF4J绑定 在编译时 都是硬连线的 , 以使用一个且只有一个特定的日志记录框架。例如,slf4j-log4j12-1.7.27.jar绑定在编译时绑定以使用log4j。在您的代码 中,除了slf4j-api-1.7.27.jar 之外 ,您只需将您选择的一个且只有一个绑定放到相应的类路径位置。不要在类路径上放置多个绑定。以下是一般概念的图解说明。

 

注意点:在springboot项目中,如果项目中有多个实现类的话,项目是会直接报错,无法运行,如下图

桥接旧的日志框架

通常,您依赖的某些组件依赖于SLF4J以外的日志记录API。您也可以假设这些组件在不久的将来不会切 换到SLF4J。为了解决这种情况,SLF4J附带了几个桥接模块,这些模块将对log4j,JCL和 java.util.logging API的调用重定向,就好像它们是对SLF4J API一样。

桥接解决的是项目中日志的遗留问题,当系统中存在之前的日志API,可以通过桥接转换到slf4j的实现

1. 先去除之前老的日志框架的依赖

2. 添加SLF4J提供的桥接组件

3. 为项目添加SLF4J的具体实现

迁移的方式:

如果我们要使用SLF4J的桥接器,替换原有的日志框架,那么我们需要做的第一件事情,就是删除掉原 有项目中的日志框架的依赖。然后替换成SLF4J提供的桥接器。

注意问题:

1. jcl-over-slf4j.jar和 slf4j-jcl.jar不能同时部署。前一个jar文件将导致JCL将日志系统的选择委托给 SLF4J,后一个jar文件将导致SLF4J将日志系统的选择委托给JCL,从而导致 无限循环 。

2. log4j-over-slf4j.jar和slf4j-log4j12.jar不能同时出现

3. jul-to-slf4j.jar和slf4j-jdk14.jar不能同时出现

4. 所有的桥接都只对Logger日志记录器对象有效,如果程序中调用了内部的配置类或者是 Appender,Filter等对象,将无法产生效果。

桥接其实就是原来项目是使用的其他日志门面或者框架作为日志管理,现在像切换到使用slf4j来作为日志门面好做统一的日志管理,在不修改代码的前提下,提出了桥接这种方式来兼容原来的老项目

SLF4J原理解析

1. SLF4J通过LoggerFactory加载日志具体的实现对象。

2. LoggerFactory在初始化的过程中,会通过performInitialization()方法绑定具体的日志实现。

3. 在绑定具体实现的时候,通过类加载器,加载org/slf4j/impl/StaticLoggerBinder.class

4. 所以,只要是一个日志实现框架,在org.slf4j.impl包中提供一个自己的StaticLoggerBinder类,在 其中提供具体日志实现的LoggerFactory就可以被SLF4J所加载

3.SLF4J 的使用

非Springboot项目

建项目

导入依赖

<!--slf4j core 使用slf4j必須添加-->  
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.27</version>
 </dependency>
 <!--slf4j 自带的简单日志实现 -->
 <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.27</version>
 </dependency>

 编写代码

public void testQuick() throws Exception {
    //打印日志信息
    LOGGER.error("error");
    LOGGER.warn("warn");
    LOGGER.info("info");
    LOGGER.debug("debug");
    LOGGER.trace("trace");
    // 使用占位符输出日志信息
    String name = "jack";
    Integer age = 18;
    LOGGER.info("用户:{},{}", name, age);
    // 将系统异常信息写入日志
    try {
        int i = 1 / 0;
    } catch (Exception e) {
        // e.printStackTrace();
        LOGGER.info("出现异常:", e);
    }
}

 输出结果

这种非springboot的项目大概流程是这样子,具体更多的使用细节这里我就不做讲解了,在开发中更多的是springboot项目,我重点介绍springboot项目

 Springboot项目(重点)

知识铺垫:

SpringBoot支持多种日志框架,包括Logback、Log4j2和Java Util Logging(JUL)。默认情况下,如果你使用SpringBoot的starters启动器,它将使用Logback作为日志框架。

  • Logback:Logback是SpringBoot默认的日志框架,它是Log4j的继任者,提供了更好的性能和可靠性。你可以通过在资源目录下创建一个logback-spring.xml文件来配置Logback。
  • Log4j2:Log4j2是Log4j的升级版,它在性能和功能上都有所提升,支持异步日志和插件机制。如果你想在SpringBoot中使用Log4j2,你需要添加相应的依赖并在配置文件中指定Log4j2作为日志框架。
  • Java Util Logging(JUL):JUL是Java SE的默认日志框架,SpringBoot可以配置使用JUL作为日志框架,但一般不推荐使用,因为它的性能和灵活性相对较差。

简单来说就是springboot项目已经帮我们内置好的日志框架,默认实现是SLF4J+logback

所以如果我们项目中没有做任何关于日志框架的处理,那么就会使用默认的组合

但在实际的开发中,往往需要对项目日志框架进行处理。开发中常用日志门面是SLF4J,常用到日志实现是logback和log42这二个具体的实现类。因为springboot项目默认使用的就是SLF4J,所以我们不需要在引入依赖的,只需要针对实现类做处理。

Springboot中使用logback

springboot项目默认的日志实现就是logback,所以我们不需要在引入依赖,如何配置logback相关的配置,有二种方式,一种在项目的配置文件种配置,一种是单独建一个文件配置(方便管理)。我这里采用单独第二种

logback会依次读取以下类型配置文件:

logback.groovy

logback-test.xml

logback.xml 如果均不存在会采用默认配置

这里我建一个logback.xml的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--
    日志输出格式:
    %-5level
    %d{yyyy-MM-dd HH:mm:ss.SSS}日期
    %c类的完整名称
    %M为method
    %L为行号
    %thread线程名称
    %m或者%msg为信息
    %n换行
    -->
    <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
    %msg:日志消息,%n是换行符-->
    <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%-5level] %c %M %L [%thread] %m%n"/>
    <!--
    Appender: 设置日志信息的去向,常用的有以下几个
    ch.qos.logback.core.ConsoleAppender (控制台)
    ch.qos.logback.core.rolling.RollingFileAppender (文件大小到达指定尺
    寸的时候产生一个新文件)
    ch.qos.logback.core.FileAppender (文件)
    -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!--输出流对象 默认 System.out 改为 System.err-->
        <target>System.out</target>
        <!--日志格式配置-->
        <encoder
                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>

    <!-- 日志文件存放目录 -->
    <property name="log_dir" value="./logs"></property>
    <!--日志文件输出appender对象-->
    <appender name="file" class="ch.qos.logback.core.FileAppender">
        <!--日志格式配置-->
        <encoder
                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!--日志输出路径-->
        <file>${log_dir}/logback.log</file>
    </appender>

    <!-- 生成html格式appender对象 -->
    <appender name="htmlFile" class="ch.qos.logback.core.FileAppender">
        <!--日志格式配置-->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <pattern>%level%d{yyyy-MM-dd
                    HH:mm:ss}%c%M%L%thread%m</pattern>
            </layout>
        </encoder>
        <!--日志输出路径-->
        <file>${log_dir}/logback.html</file>
    </appender>

    <!-- 日志文件拆分和归档的appender对象-->
    <appender name="rollFile"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志格式配置-->
        <encoder
                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
        <!--日志输出路径-->
        <file>${log_dir}/roll_logback.log</file>
        <!--指定日志文件拆分和压缩规则-->
        <rollingPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--通过指定压缩文件名称,来确定分割文件方式-->
            <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!--文件拆分大小-->
            <maxFileSize>50MB</maxFileSize>
        </rollingPolicy>
    </appender>
    <!--
    用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
    <loger>仅有一个name属性,一个可选的level和一个可选的addtivity属性
    name:
    用来指定受此logger约束的某一个包或者具体的某一个类。
    level:
    用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和
    OFF,
    如果未设置此属性,那么当前logger将会继承上级的级别。
    additivity:
    是否向上级loger传递打印信息。默认是true。
    <logger>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个
    logger
    -->
    <!--
    也是<logger>元素,但是它是根logger。默认debug
    level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL
    和 OFF,
    <root>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个
    logger。
    -->
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="rollFile"/>
    </root>
</configuration>

编写测试类

public class LogbackTest {

    public static final Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class);
    @Test
    public void logbackTest(){
        LOGGER.error("error");  //错误信息,不会影响程序运行
        LOGGER.warn("warn");    //警告信息,表示系统运行可能出现的异常
        LOGGER.info("info");    //提示信息,记录系统运行,io操作等
        LOGGER.debug("debug");  //调试信息,一般在开发中使用
        LOGGER.trace("trace");  //追踪信息,记录程序所有的流程信息

        // 占位符输出日志
        String name = "jack";
        Integer age = 18;
        LOGGER.info("用户姓名:{},年龄:{}",name,age);
        int i = 1;
        try {
            i = i/0;
        } catch (Exception e) {
            LOGGER.info("出现异常",e);
        }
    }
}

运行效果:

未配置logback.xml前的输出效果

配置后的输出效果

总结:在springboot 使用logback非常的简单,你只需要通过配置文件去配置它就好了

Springboot中使用log4j2

 因为springboot项目内置日志实现是logback,所以如果我们要使用log42的话,需要移除默认的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!--排除默认spring-boot-starter-logging启动器-->
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

加入 log4j2的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

 

在src/main/resources目录下创建一个名为log4j2-spring.xml的配置文件,Spring Boot会默认加载这个配置文件。Spring Boot官方推荐优先使用带有-spring的文件名作为日志配置。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <!-- 定义全局变量,日志文件路径和格式 -->
    <Properties>
        <Property name="log.path">./dev</Property>
        <Property name="log.name">log4j2</Property>
        <Property name="file.pattern">%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{50} - %msg%n</Property>
    </Properties>

    <!-- 控制台输出配置 -->
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="${file.pattern}"/>
            <ThresholdFilter level="DEBUG"/>
        </Console>

        <!-- 文件输出配置 -->
        <RollingFile name="INFO_FILE" fileName="${log.path}/${log.name}.log4j2.log"
                     filePattern="${log.path}/%d{yyyy-MM-dd}/${log.name}.info.%d{yyyy-MM-dd}-%i.log">
            <PatternLayout pattern="${file.pattern}"/>
            <LevelMatchFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 每个文件最大10MB -->
            <SizeBasedTriggeringPolicy size="10MB"/>
            <!-- 最多保留30天的历史记录 -->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>

        <!-- 文件输出配置 -->
        <RollingFile name="ERROR_FILE" fileName="${log.path}/${log.name}.error.log"
                     filePattern="${log.path}/%d{yyyy-MM-dd}/${log.name}.error.%d{yyyy-MM-dd}-%i.log">
            <PatternLayout pattern="${file.pattern}"/>
            <LevelMatchFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <!-- 每个文件最大10MB -->
            <SizeBasedTriggeringPolicy size="10MB"/>
            <!-- 最多保留30天的历史记录 -->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>
    </Appenders>

    <!-- 设置root logger -->
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="STDOUT"/>
            <AppenderRef ref="INFO_FILE"/>
            <AppenderRef ref="ERROR_FILE"/>
        </Root>
    </Loggers>
</Configuration>

 运行效果

 如何是出现如上图,就代表使用的是log4j2这个日志实现了

总的来说,推荐使用Logback,配置简单,性能也还不错,而且是SpringBoot的默认日志框架

这里对于logback和log4j2的使用只是基本的使用,对于更多的使用细节,后续我会分别出对应实现框架的文章,文章到这里就结束了,如有不足,欢迎指正

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

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

相关文章

【CSS in Depth 2精译】2.5 无单位的数值与行高

当前内容所在位置 第一章 层叠、优先级与继承第二章 相对单位 2.1 相对单位的威力2.2 em 与 rem2.3 告别像素思维2.4 视口的相对单位2.5 无单位的数值与行高 ✔️2.6 自定义属性2.7 本章小结 2.5 无单位的数值与行高 有些属性允许使用无单位的数值&#xff08;unitless value…

Linux:DHCP服务配置

目录 一、DHCP概述以及DHCP的好处 1.1、概述 1.2、DHCP的好处 二、DHCP的模式与分配方式 2.1、模式 2.2、DHCP的分配方式 三、DHCP工作原理 四、安装DHCP服务 五、DHCP局部配置并且测试 5.1、subnet 网段声明 5.2、客户机预留指定的固定ip地址 一、DHCP概述以及DHCP…

【Java13】包

“包”这个机制&#xff0c;类似于分组。主要作用是区分不同组内的同名类。例如&#xff0c;高三三班有一个“王五”&#xff0c;高二八班也有一个“王五”。高三三班和高三八班就是两个不同的包。 Java中的包&#xff08;package&#xff09;机制主要提供了类的多层命名空间&…

驾校管理系统设计

驾校管理系统设计旨在提高驾校运营效率、学员管理、教练安排、考试预约、财务结算等方面的能力。以下是一个基本的设计框架&#xff0c;包括关键模块和数据表设计&#xff1a; 1. 系统架构设计 前端界面&#xff1a;提供给学员、教练和管理员使用的Web界面或移动应用&#xf…

51单片机STC89C52RC——16.1 五项四线步进电机

目的/效果 让步进电机 正向转90度&#xff0c;逆向转90度 一&#xff0c;STC单片机模块 二&#xff0c;步进电机 2.2 什么是步进电机&#xff1f; 步进电机可以理解为&#xff1a;是一个按照固定步幅运动的“小型机器”。它与普通电机不同点在于&#xff0c;普通电机可以持…

插入排序——C语言

假设我们现在有一个数组&#xff0c;对它进行排序&#xff0c;插入排序的算法如同它的名字一样&#xff0c;就是将元素一个一个插入到合适的位置&#xff0c;那么&#xff0c;该如何做呢&#xff1f; 如果我们要从小到大进行排序的话&#xff0c;步骤如下&#xff1a; 1.对于…

WAWA鱼曲折的大学四年回忆录

声明&#xff1a;本文内容纯属个人主观臆断&#xff0c;如与事实不符&#xff0c;请参考事实 前言&#xff1a; 早想写一下大学四年的总结了&#xff0c;但总是感觉无从下手&#xff0c;不知道从哪里开始写&#xff0c;通过这篇文章主要想做一个记录&#xff0c;并从现在的认…

大数据之路 读书笔记 Day4 数据同步

回顾&#xff1a; Day 3 总结了无限客户端的日志采集 大数据之路 读书笔记 Day 3Day 2总结了浏览器端的日志采集 大数据之路 读书笔记 Day 2 数据同步 阿里数据体系中的数据同步&#xff0c;主要指的是在不同的数据存储系统之间进行数据的传输与更新&#xff0c;以保证数据的一…

自用款 复制粘贴工具 Paste macOS电脑适配

Paste是一款专为Mac和iOS用户设计的剪贴板管理工具&#xff0c;它提供了强大的剪贴板增强功能。Paste能够实时记录用户复制和剪切的内容&#xff0c;包括文本、图片、链接等多种数据类型&#xff0c;并形成一个可视化的剪贴板历史记录&#xff0c;方便用户随时访问和检索。此外…

【密码学】密码学中的四种攻击方式和两种攻击手段

在密码学中&#xff0c;攻击方式通常指的是密码分析者试图破解加密信息或绕过安全机制的各种策略。根据密码分析者对明文、密文以及加密算法的知识程度&#xff0c;攻击可以分为以下四种基本类型&#xff1a; 一、四种攻击的定义 &#xff08;1&#xff09;唯密文攻击(COA, C…

蚂蚁全媒体总编刘鑫炜谈新媒体时代艺术家如何创建及提升个人品牌

新媒体时代艺术家如何创建及提升个人品牌形象——专访蚂蚁全媒体总编刘鑫炜 图为蚂蚁全媒体总编刘鑫炜 在新媒体风潮席卷全球的今天&#xff0c;传统艺术与新媒体技术的融合越来越紧密。这种变革不仅改变了艺术作品的呈现方式&#xff0c;也给艺术家们提供了更多的可能性。那么…

python 10个自动化脚本

目录 &#x1f31f; 引言 &#x1f4da; 理论基础 &#x1f6e0;️ 使用场景与代码示例 场景一&#xff1a;批量重命名文件 场景二&#xff1a;自动下载网页内容 场景三&#xff1a;数据清洗 场景四&#xff1a;定时执行任务 场景五&#xff1a;自动化邮件发送 场景六…

【面向就业的Linux基础】从入门到熟练,探索Linux的秘密(十二)-管道、环境变量、常用命令

大致介绍了一下管道、环境变量、一些常用的基本命令&#xff0c;可以当作学习笔记收藏学习一下&#xff01;&#xff01;&#xff01; 文章目录 前言 一、管道 二、环境变量 1.概念 2.查看 3.修改 4.常用环境变量 三、系统状况 总结 前言 大致介绍了一下管道、环境变量、一些常…

【因果推断】优惠券政策对不同店铺的影响

这次依然是用之前rossmann店铺竞赛的数据集。 之前的数据集探索处理在这里已经做过了&#xff0c;此处就不再赘述了CSDN链接 数据集地址&#xff1a;竞赛链接 这里探讨数据集中Promo2对于每家店铺销售额的影响。其中&#xff0c;Promo2是一个基于优惠券的邮寄活动&#xff0c;发…

ZYNQ-LINUX环境C语言利用Curl库实现HTTP通讯

前言 在Zynq-Linux环境中&#xff0c;需要使用C语言来编写APP时&#xff0c;访问HTTP一般可以使用Curl库来实现&#xff0c;但是在Zynq的SDK中&#xff0c;并没有集成该库&#xff0c;在寻找了很多资料后找到了一种使用很方便的额办法。这篇文章主要记录一下移植Curl的过程。 …

将iStoreOS部署到VMware ESXi变成路由器

正文共&#xff1a;888 字 19 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面把iStoreOS部署到了VMware workstation上&#xff08;将iStoreOS部署到VMware Workstation&#xff09;。如果想把iStoreOS直接部署到ESXi上&#xff0c;你会发现转换镜像不能直接生成OVF或者OV…

Redis源码整体结构

一 前言 Redis源码研究为什么先介绍整体结构呢?其实也很简单,作为程序员的,要想对一个项目有快速的认知,对项目整体目录结构有一个清晰认识,有助于我们更好的了解这个系统。 二 目录结构 Redis源码download到本地之后,对应结构如下: 从上面的截图可以看出,Redis源码一…

【2024_CUMCM】T检验、F检验、卡方检验

T检验 T检验主要用于比较两组数据的均值差异&#xff0c;适用于小样本数据分析。它可以分为单样本T检验、独立样本T检验和配对样本T检验。 单样本T检验用于比较一个样本与已知的总体均值差异&#xff0c;独立样本T检验用于比较两个独立样本的均值差异&#xff0c;配对样本T检…

【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【21】【购物车】

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【21】【购物车】 购物车需求描述购物车数据结构数据Model抽取实现流程&#xff08;参照京东&#xff09;代码实现参考 购物车需求描述 用户可以在登录状态下将商品添加到购物车【用户购物…

从FasterTransformer源码解读开始了解大模型(2.1)代码通读03

从FasterTransformer源码解读开始了解大模型&#xff08;2.2&#xff09;代码解读03-forward函数 写在前面的话 本篇的内容继续解读forward函数&#xff0c;从650行开始进行解读 零、输出Context_embeddings和context_cum_log_probs的参数和逻辑 从653行开始&#xff0c;会…