springboot中将logback切换为log4j2

news/2025/3/19 19:39:31/

前言
springboot默认使用logback作为日志记录框架,常见的日志记录框架有log4j、logback、log4j2。这篇文章我们来学习怎样将logbak替换为log4j2。
一、为什么使用log4j2?
我们在项目中经常使用一个叫SLF4J的依赖,它是做什么的呢?

slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,它的接口并不能独立使用,需要和具体的日志框架实现配合使用(如log4j、logback、log4j2)。

log4j是apache实现的一个开源日志组件。
logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,是slf4j的原生实现。
Log4j2是log4j 1.x和logback的改进版,性能最高。
log4j2异步记录日志使用了disruptor框架,性能得到了提高,记录日志的流程如下:

在这里插入图片描述
几种日志框架的性能测试对比如下:

 在这里插入图片描述

 

二、使用步骤

1.引入库

gradle:

//引入log4j2
api 'org.springframework.boot:spring-boot-starter-log4j2'
api "com.lmax:disruptor:3.4.4"//删除logback依赖
configurations {api.exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'api.exclude group: 'ch.qos.logback', module: 'logback-access'api.exclude group: 'ch.qos.logback', module: 'logback-classic'api.exclude group: 'ch.qos.logback', module: 'logback-core'
}

 maven:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><!-- 排除掉logging,不使用logback,改用log4j2 --><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>
<!-- disruptor -->
<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.4</version>
</dependency>

2.编写log4j2配置文件

在application.properties中引入配置文件

logging.config=classpath:log4j2-spring.xml

在resources下添加log4j2-spring.xml配置文件
以下是我在项目中的配置,注意的是使用AsyncLogger才会使用disruptor提高性能。如果使用的AsyncAppender,则使用的是类似logback一样的队列的方式做异步记录。

<?xml version="1.0" encoding="UTF-8"?><!--Configuration 后面的 status,这个用于设置 log4j2 自身内部的信息输出级别,可以不设置,当设置成 trace 时,你会看到 log4j2 内部各种详细输出-->
<!--monitorInterval:Log4j2 能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="error" monitorInterval="30"><!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --><!--变量配置--><properties><!-- 格式化输出:%date 表示日期,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度 %msg:日志消息,%n 是换行符--><!-- %logger{36} 表示 Logger 名字最长 36 个字符 --><property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%logger{50}:%L] - %msg%n"/><property name="LOG_CONSOLE_PATTERN" value="%style{%d{ISO8601}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}: %msg%n%style{%throwable}{red}"/><!-- 定义日志存储的路径 --><property name="FILE_PATH" value="logs"/><property name="FILE_NAME" value="newframe"/></properties><Appenders><!--*********************控制台日志***********************--><Console name="consoleAppender" target="SYSTEM_OUT"><!--设置日志格式及颜色--><PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/></Console><!--info级别日志--><!-- 这个会打印出所有的info及以上级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--><RollingFile name="infoFileAppender"fileName="${FILE_PATH}/${FILE_NAME}/log_info.log"filePattern="${FILE_PATH}/${FILE_NAME}/log-info-%d{yyyy-MM-dd}_%i.log.gz"append="true"><!--设置日志格式--><PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/><Filters><!--过滤掉warn及更高级别日志--><ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL" /><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/></Filters><Policies><!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:interval,integer型,指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位,比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,那么假设上次封存日志的时间为00:00,则下次封存日志的时间为04:00,之后的封存时间依次为08:00,12:00,16:00--><TimeBasedTriggeringPolicy interval="1"/><SizeBasedTriggeringPolicy size="10MB"/></Policies><!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下当天 7 个文件后开始覆盖--><DefaultRolloverStrategy max="30"><!-- 删除处理策略,在配置的路径中搜索,maxDepth 表示往下搜索的最大深度 --><Delete basePath="${FILE_PATH}/${FILE_NAME}/" maxDepth="2"><!-- 文件名搜索匹配,支持正则 --><IfFileName glob="*.log.gz"/><!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用另外, 数字最好 >2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!--><!--7天--><IfLastModified age="7d"/></Delete></DefaultRolloverStrategy></RollingFile><!--warn级别日志--><!-- 这个会打印出所有的warn及以上级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--><RollingFile name="warnFileAppender"fileName="${FILE_PATH}/${FILE_NAME}/log_warn.log"filePattern="${FILE_PATH}/${FILE_NAME}/log-warn-%d{yyyy-MM-dd}_%i.log.gz"append="true"><!--设置日志格式--><PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/><Filters><!--过滤掉error及更高级别日志--><ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL" /><ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/></Filters><Policies><!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:interval,integer型,指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位,比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,那么假设上次封存日志的时间为00:00,则下次封存日志的时间为04:00,之后的封存时间依次为08:00,12:00,16:00--><TimeBasedTriggeringPolicy interval="1"/><SizeBasedTriggeringPolicy size="10MB"/></Policies><!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下当天 7 个文件后开始覆盖--><DefaultRolloverStrategy max="30"><!-- 删除处理策略,在配置的路径中搜索,maxDepth 表示往下搜索的最大深度 --><Delete basePath="${FILE_PATH}/${FILE_NAME}/" maxDepth="2"><!-- 文件名搜索匹配,支持正则 --><IfFileName glob="*.log.gz"/><!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用另外, 数字最好 >2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!--><!--7天--><IfLastModified age="7d"/></Delete></DefaultRolloverStrategy></RollingFile><!--error级别日志--><!-- 这个会打印出所有的error及以上级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--><RollingFile name="errorFileAppender"fileName="${FILE_PATH}/${FILE_NAME}/log_error.log"filePattern="${FILE_PATH}/${FILE_NAME}/log-error-%d{yyyy-MM-dd}_%i.log.gz"append="true"><!--设置日志格式--><PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/><Filters><ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/></Filters><Policies><!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:interval,integer型,指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位,比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,那么假设上次封存日志的时间为00:00,则下次封存日志的时间为04:00,之后的封存时间依次为08:00,12:00,16:00--><TimeBasedTriggeringPolicy interval="1"/><SizeBasedTriggeringPolicy size="10MB"/></Policies><!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下当天 7 个文件后开始覆盖--><DefaultRolloverStrategy max="30"><!-- 删除处理策略,在配置的路径中搜索,maxDepth 表示往下搜索的最大深度 --><Delete basePath="${FILE_PATH}/${FILE_NAME}/" maxDepth="2"><!-- 文件名搜索匹配,支持正则 --><IfFileName glob="*.log.gz"/><!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用另外, 数字最好 >2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!--><!--7天--><IfLastModified age="7d"/></Delete></DefaultRolloverStrategy></RollingFile><!--<Async name="Async" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></Async>--></Appenders><Loggers><AsyncLogger name="org.apache.http" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="io.lettuce" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="io.netty" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.quartz" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.springframework" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.springdoc" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="druid.sql" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="io.undertow" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="sun.rmi" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="com.sun.mail" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="javax.management" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="de.codecentric" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.hibernate.validator" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.mybatis.spring.mapper" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.xnio" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="springfox" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="com.baomidou" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="io.micrometer.core" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="Validator" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.neo4j" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.apache.zookeeper" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="org.apache.curator" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="oshi.util" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="net.javacrumbs" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncLogger name="com.atomikos" level="info" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncLogger><AsyncRoot level="debug" includeLocation="true" additivity="false"><AppenderRef ref="infoFileAppender"/><AppenderRef ref="warnFileAppender"/><AppenderRef ref="errorFileAppender"/><AppenderRef ref="consoleAppender"/></AsyncRoot></Loggers><!--Logger 节点用来单独指定日志的形式,比如要为指定包下的 class 指定不同的日志级别等。--><!--然后定义 loggers,只有定义了 logger 并引入的 appender,appender 才会生效--><!--<Loggers><Logger name="java.sql" level="debug" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="com.sxd.swapping.dao.mybatis" level="debug" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.apache.ibatis" level="debug" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="sun.rmi.transport.tcp" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.apache.http" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="com.sun.mail.smtp" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="javax.management" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="sun.rmi" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="de.codecentric" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="druid.sql.Connection" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="druid.sql.Statement" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="druid.sql.ResultSet" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.hibernate.validator" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.mybatis.spring.mapper" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.xnio.nio" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="springfox.documentation" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="springfox.bean" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="com.baomidou.mybatisplus.core" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="io.undertow" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="io.micrometer.core" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="com.baomidou.mybatisplus.extension.spring" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="Validator" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="io.lettuce" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="io.netty" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.boot.actuate.redis.RedisReactiveHealthIndicator" level="error" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.neo4j.driver" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.apache.zookeeper" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.apache.curator.framework.recipes.cache" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="oshi.util.platform.windows" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.quartz.core" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.quartz.simpl" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="net.javacrumbs.shedlock.core.DefaultLockingTaskExecutor" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="com.atomikos.jdbc.AbstractDataSourceBean" level="warn" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="com.atomikos.jdbc.AtomikosConnectionProxy" level="error" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.boot.actuate.mail" level="error" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.web" level="info" additivity="false" ><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.context" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.data" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.beans" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.core" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.jdbc" level="info" additivity="false"><AppenderRef ref="Async"/></Logger><Logger name="org.springframework.messaging" level="info" additivity="false"><AppenderRef ref="Async"/></Logger>&lt;!&ndash; 根日志设置 &ndash;&gt;<Root level="debug" additivity="false"><AppenderRef ref="Async"/></Root></Loggers>--></configuration>

总结

log4j2使用了两种方式记录日志:AsyncAppender和AsyncLogger,上面我们的配置采用了AsyncLogger,性能最佳。
1、AsyncAppender使用队列异步记录日志,但是一旦队列已满,appender线程需要等待。
2、AsyncLogger是采用Disruptor,通过环形队列无阻塞队列作为缓冲,多生产者多线程的竞争是通过CAS实现,无锁化实现,可以降低极端大的日志量时候的延迟尖峰,Disruptor 可是号称一个线程里每秒处理600万订单的高性能队列。


下图是官方给出的性能对比:

在这里插入图片描述

 


http://www.ppmy.cn/news/123472.html

相关文章

5月31号软件资讯更新合集......

Guava 32.0 发布&#xff0c;Google 的核心 Java 工具库 Guava 是 Google 的一套核心 Java 库&#xff0c;包括新的集合类型&#xff08;如 multimap 和 multiset&#xff09;、图库&#xff0c;以及用于并发、I/O、散列、缓存、基元、字符串等实用工具。它被广泛用于 Google …

基于AT89C51单片机的电子琴设计与仿真

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/87848430?spm1001.2014.3001.5503 源码获取 主要内容&#xff1a; 设计一个简易的电子琴&#xff0c;至少具有可以弹奏并发出不同的音调。电子琴方案主要分为实验…

C++学习之旅-入门永远的HelloWorld变量的基础

文章目录 创建文件(Hello World)注释变量的使用常量标识符命名规则数据类型整形sizeof关键字实型(浮点类型)字符型转义字符字符串类型布尔类型数据的输入加减乘除运算算数运算逻辑运算 程序流程结构选择结构循环结构 跳转语句举例(while循环break)举例(for循环contine) 跳转语句…

功率信号源驱动电路工作原理是什么

功率信号源驱动电路是一种能够将低功率、微弱的信号放大到足够高的功率水平的电路。在现代通信、医疗、工业等领域中&#xff0c;功率信号源驱动电路被广泛应用。下面&#xff0c;我们将对功率信号源驱动电路进行详细的介绍。 图&#xff1a;ATG-2000系列功率信号源 功率信号源…

二进制安装K8S

阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 (aliyun.com)https://developer.aliyun.com/mirror/所有节点yum源更换为 &#xff0c;按照aliyun给的容器里面的kubenetes源和docker源&#xff0c;当然最好把之前的centos源也换成aliyun的 所有节点安装docker yum install -…

微控制器(单片机)的中断系统及应用

文章目录 1. 什么是中断1.1 中断的概念1.2 中断源1.2.1 中断源的种类 2. 中断寄存器2.1 TCON寄存器2.2 SCON寄存器2.3 IE寄存器2.4 IP寄存器 3. 中断处理流程3.1 定时器中断实操3.2 外部中断实操3.3 思考题&#xff1a; 4. 最重要的事 1. 什么是中断 1.1 中断的概念 中断是指…

操作系统中的中断控制

本文为随笔&#xff0c;更多细节可关注微信公众号&#xff1a;emOsprey uCOS II MAX_SYSCALL_INTERRUPT_PRIORITY EQU 3 ; 屏蔽低于优先级 2 的中断&#xff0c;即抢占优先级设置为 0~2 将被屏蔽&#xff0c;3不屏蔽 OS_CPU_SR_SaveMRS R0, BASEPRI ; 读取 PRI…

【中断篇】中断控制器及中断检测时序

&#x1f31f;&#x1f31f;&#x1f31f;博主主页&#xff1a;MuggleZero &#x1f31f;&#x1f31f;&#x1f31f; 《ARMv8架构初学者笔记》专栏地址&#xff1a;《ARMv8架构初学者笔记》 GIC-500控制器支持GICv3架构&#xff0c;具有以下中断类型&#xff1a; SGI&#xff…