在现代Java应用开发中,日志(Logging)是系统监控、调试、故障排查和性能分析的核心工具。一个高效、灵活、可配置的日志系统,不仅能帮助开发者快速定位问题,还能为运维团队提供宝贵的运行时信息。在Java生态系统中,Log4jSLF4J 是两个最广泛使用的日志框架,它们各具特色,常被结合使用以实现最佳实践。

本文将深入探讨Java日志管理的核心概念,详细介绍 Log4j 2.xSLF4J 的使用方法、配置技巧、性能优化以及最佳实践。通过大量代码示例,我们将从零开始构建一个功能完备的日志系统,涵盖控制台输出、文件记录、异步日志、日志级别、格式化、滚动策略等关键主题。


一、日志系统的重要性

在没有日志的系统中,当程序出现异常或性能问题时,开发者往往只能“盲人摸象”,依靠猜测和重现来定位问题。日志系统则提供了以下关键价值:

  1. 调试与排错:记录程序执行流程、变量状态、异常堆栈,帮助快速定位Bug。
  2. 监控与告警:通过分析日志中的错误、警告信息,实现系统健康监控。
  3. 审计与合规:记录用户操作、系统事件,满足安全审计要求。
  4. 性能分析:记录方法执行时间、数据库查询耗时,辅助性能优化。
  5. 运行时洞察:了解系统在生产环境中的实际行为,指导架构演进。

二、Java日志框架发展简史

Java的日志生态经历了多个阶段的演进:

  1. JDK 1.4 之前:无标准日志机制,开发者使用 System.out.println()
  2. JDK 1.4 (2002):引入 java.util.logging(JUL),但功能有限,配置复杂。
  3. Log4j (2001):由Ceki Gülcü开发,功能强大,迅速成为事实标准。
  4. Commons Logging (JCL):Apache提供的日志门面,用于桥接不同日志实现。
  5. SLF4J (Simple Logging Facade for Java):由Ceki Gülcü开发,作为更优雅的日志门面。
  6. Logback:SLF4J的原生实现,性能优于Log4j。
  7. Log4j 2.x:Apache重启Log4j项目,解决1.x的性能和架构问题,支持插件化、异步日志等。

目前,SLF4J + Log4j 2.xSLF4J + Logback 是最主流的组合。


三、SLF4J:日志门面(Facade)

SLF4J(Simple Logging Facade for Java) 不是一个日志实现,而是一个日志门面。它为各种日志框架(如Log4j、Logback、JUL)提供了一个统一的API,使应用程序与具体的日志实现解耦。

3.1 为什么需要日志门面?

假设你的项目直接依赖Log4j,代码中使用 org.apache.log4j.Logger。如果未来想切换到Logback,你必须修改所有日志调用代码,工作量巨大且容易出错。

而使用SLF4J,你的代码只依赖 org.slf4j.Logger,通过更换**绑定库(Binding)**即可切换底层实现,无需修改业务代码。

3.2 SLF4J 核心组件

  • org.slf4j.Logger:日志记录接口,定义 debug(), info(), warn(), error() 等方法。
  • org.slf4j.LoggerFactory:工厂类,用于获取 Logger 实例。
  • 绑定库(Binding):将SLF4J API桥接到具体日志实现,如 slf4j-log4j12, log4j-slf4j-impl, logback-classic

3.3 SLF4J 基本使用示例

1. 添加Maven依赖
<!-- SLF4J API -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.36</version>
</dependency><!-- Log4j 2.x 绑定 -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.19.0</version>
</dependency>

注意:确保项目中只有一个SLF4J绑定,否则会报错。

2. 编写日志代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class UserService {// 获取Logger实例,通常以类名命名private static final Logger logger = LoggerFactory.getLogger(UserService.class);public void createUser(String username) {logger.debug("Creating user: {}", username); // 使用占位符,避免字符串拼接try {// 模拟业务逻辑if (username == null || username.trim().isEmpty()) {throw new IllegalArgumentException("Username cannot be null or empty");}logger.info("User '{}' created successfully", username);} catch (Exception e) {logger.error("Failed to create user: {}", username, e); // 记录异常堆栈throw e;}}
}
3. 测试
public class LoggingDemo {public static void main(String[] args) {UserService userService = new UserService();userService.createUser("alice");userService.createUser(""); // 触发异常}
}

输出

14:23:45.123 [main] DEBUG com.example.UserService - Creating user: alice
14:23:45.124 [main] INFO  com.example.UserService - User 'alice' created successfully
14:23:45.125 [main] DEBUG com.example.UserService - Creating user: 
14:23:45.125 [main] ERROR com.example.UserService - Failed to create user: 
java.lang.IllegalArgumentException: Username cannot be null or emptyat com.example.UserService.createUser(UserService.java:12)...

3.4 SLF4J 占位符(Placeholders)

SLF4J支持 {} 占位符,这是最佳实践,因为:

  • 避免不必要的字符串拼接(当日志级别为INFO时,DEBUG日志不会输出,但字符串拼接仍会执行)。
  • 支持自动转换对象为字符串。
  • 支持多参数。
logger.debug("User {} logged in from IP {}", username, ip);
logger.error("Database connection failed", exception); // 异常作为最后一个参数

四、Log4j 2.x:高性能日志实现

Log4j 2.x 是Apache Log4j的下一代版本,解决了1.x的性能瓶颈和架构缺陷,提供了:

  • 极高的性能(异步日志性能提升10倍以上)
  • 插件化架构
  • 自动重新加载配置
  • 高级过滤功能
  • 多种Appender(输出目的地)
  • Lambda表达式支持

4.1 Log4j 2.x 核心组件

Log4j 2.x 的核心是 Logger, Appender, Layout, Level 四大组件。

1. Logger(记录器)
  • 负责生成日志事件。
  • 具有名称(通常为类的全限定名)和日志级别。
  • 支持层级继承(如 com.example.service.UserService 继承 com.example.service 的配置)。
2. Appender(输出器)
  • 决定日志输出到哪里。
  • 常见Appender:
    • ConsoleAppender:输出到控制台
    • FileAppender / RollingFileAppender:输出到文件,支持滚动
    • SocketAppender:通过网络发送
    • JDBCAppender:写入数据库
    • KafkaAppender:发送到Kafka
3. Layout(布局)
  • 定义日志的输出格式。
  • 常用Layout:
    • PatternLayout:自定义格式
    • JsonLayout:JSON格式
    • XmlLayout:XML格式
4. Level(日志级别)
  • 定义日志的严重程度。
  • 优先级从高到低:
    • OFF (最高,关闭所有日志)
    • FATAL
    • ERROR
    • WARN
    • INFO
    • DEBUG
    • TRACE
    • ALL (最低,记录所有日志)

注意:Logger的级别决定了它能接收哪些级别的日志。例如,级别为INFO的Logger会接收INFOWARNERRORFATAL日志,但忽略DEBUGTRACE


五、Log4j 2.x 配置详解

Log4j 2.x 支持多种配置方式:XML、JSON、YAML、Properties、Java代码。我们以最常用的 XML 为例。

5.1 基本XML配置文件(log4j2.xml)

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30"><!-- 定义公共属性 --><Properties><Property name="LOG_PATH">logs</Property><Property name="FILE_NAME">app</Property></Properties><Appenders><!-- 控制台Appender --><Console name="ConsoleAppender" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console><!-- 文件Appender(滚动策略) --><RollingFile name="RollingFileAppender"fileName="${LOG_PATH}/${FILE_NAME}.log"filePattern="${LOG_PATH}/${FILE_NAME}-%d{yyyy-MM-dd}-%i.log.gz"><PatternLayout><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</pattern></PatternLayout><!-- 滚动策略:基于时间和大小 --><Policies><!-- 每天滚动一次 --><TimeBasedTriggeringPolicy interval="1" modulate="true"/><!-- 文件大小超过100MB时滚动 --><SizeBasedTriggeringPolicy size="100MB"/></Policies><!-- 策略:保留最多30天的日志 --><DefaultRolloverStrategy max="30"/></RollingFile></Appenders><Loggers><!-- 根Logger --><Root level="info"><AppenderRef ref="ConsoleAppender"/><AppenderRef ref="RollingFileAppender"/></Root><!-- 特定包的Logger(可选) --><Logger name="com.example.service" level="debug" additivity="false"><AppenderRef ref="RollingFileAppender"/></Logger></Loggers>
</Configuration>

5.2 配置项详解

  • status="WARN":Log4j内部日志级别,用于诊断配置错误。
  • monitorInterval="30":每隔30秒检查配置文件是否修改,自动重新加载。
  • <Properties>:定义变量,便于复用。
  • <Console>:输出到控制台。
  • <RollingFile>
    • fileName:当前日志文件路径。
    • filePattern:归档文件命名模式,%d{yyyy-MM-dd}按天,%i为序号,.gz表示压缩。
  • <Policies>:触发滚动的策略。
    • TimeBasedTriggeringPolicy:按时间滚动。
    • SizeBasedTriggeringPolicy:按大小滚动。
  • <DefaultRolloverStrategy>:滚动后的保留策略,max="30"表示最多保留30个归档文件。
  • <Root>:根Logger,所有Logger的默认父级。
  • <Logger>:自定义Logger,可覆盖特定包的日志级别和Appender。
    • additivity="false":关闭累加性,避免日志被父Logger重复输出。

5.3 高级Appender配置

1. 异步日志(AsyncAppender)

异步日志能显著提升性能,尤其在高并发场景。

<Async name="AsyncAppender"><AppenderRef ref="RollingFileAppender"/>
</Async><Loggers><Root level="info"><AppenderRef ref="ConsoleAppender"/><AppenderRef ref="AsyncAppender"/> <!-- 使用异步Appender --></Root>
</Loggers>

注意:Log4j 2.x 还支持 LMAX Disruptor 实现的异步Logger,性能更高。

2. JSON格式日志

便于日志收集系统(如ELK)解析。

<RollingFile name="JsonFileAppender" ...><JsonLayout compact="true" eventEol="true"/><Policies>...</Policies>
</RollingFile>

输出示例

{"timeMillis":1719843825123,"thread":"main","level":"INFO","loggerName":"com.example.UserService","message":"User 'alice' created successfully","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":1,"threadPriority":5}
3. 过滤器(Filters)

根据条件决定是否记录日志。

<RollingFile name="FilteredFileAppender" ...><PatternLayout pattern="%d %p %c{1.} [%t] %m%n"/><ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/><Policies>...</Policies>
</RollingFile>
  • ThresholdFilter:级别过滤器,WARN及以上级别被拒绝(DENY),低于则中立(NEUTRAL)。
  • onMatch:匹配时的动作(ACCEPT, DENY, NEUTRAL)。
  • onMismatch:不匹配时的动作。

六、SLF4J与Log4j 2.x集成实战

我们已经通过Maven依赖将SLF4J与Log4j 2.x集成。现在通过一个完整示例演示其工作流程。

6.1 项目结构

src/
├── main/
│   ├── java/
│   │   └── com/example/
│   │       ├── UserService.java
│   │       └── LoggingDemo.java
│   └── resources/
│       ├── log4j2.xml
│       └── application.properties

6.2 日志配置优化

增强 log4j2.xml 功能:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30"><Properties><Property name="LOG_PATH">./logs</Property><Property name="APP_NAME">myapp</Property><Property name="MAX_FILE_SIZE">100MB</Property><Property name="MAX_FILES">10</Property></Properties><Appenders><!-- 彩色控制台输出 --><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%highlight{%d{ISO8601} [%t] %-5level %logger{36} - %msg%n}{FATAL=red blink, ERROR=red, WARN=yellow bold, INFO=green, DEBUG=cyan, TRACE=blue}"/></Console><!-- 按天滚动的主日志文件 --><RollingFile name="RollingFile"fileName="${LOG_PATH}/${APP_NAME}.log"filePattern="${LOG_PATH}/${APP_NAME}-%d{yyyy-MM-dd}-%i.log"><PatternLayout><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</pattern></PatternLayout><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="${MAX_FILE_SIZE}"/></Policies><DefaultRolloverStrategy max="${MAX_FILES}"/></RollingFile><!-- 专门记录ERROR日志的文件 --><RollingFile name="ErrorFile"fileName="${LOG_PATH}/${APP_NAME}-error.log"filePattern="${LOG_PATH}/${APP_NAME}-error-%d{yyyy-MM-dd}-%i.log"><PatternLayout pattern="%d %p %c [%t] %m%n"/><Policies><TimeBasedTriggeringPolicy/></Policies><DefaultRolloverStrategy max="30"/><!-- 只记录ERROR及以上级别 --><ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/></RollingFile><!-- 异步Appender --><Async name="Async"><AppenderRef ref="RollingFile"/><AppenderRef ref="ErrorFile"/></Async></Appenders><Loggers><!-- 业务包:DEBUG级别 --><Logger name="com.example" level="debug" additivity="false"><AppenderRef ref="Async"/></Logger><!-- 第三方库:INFO级别,避免过多日志 --><Logger name="org.springframework" level="info"/><Logger name="org.hibernate" level="warn"/><!-- 根Logger --><Root level="info"><AppenderRef ref="Console"/></Root></Loggers>
</Configuration>

6.3 代码示例:用户服务与异常处理

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class UserService {private static final Logger logger = LoggerFactory.getLogger(UserService.class);public void processUser(String username) {logger.debug("Processing user: {}", username);// 模拟不同场景if (username == null) {logger.warn("Null username provided, using default");username = "anonymous";}if (username.length() < 3) {logger.error("Username '{}' is too short", username);throw new IllegalArgumentException("Username too short");}logger.info("Successfully processed user: {}", username);}
}
public class LoggingDemo {private static final Logger logger = LoggerFactory.getLogger(LoggingDemo.class);public static void main(String[] args) {logger.info("Application started");UserService userService = new UserService();try {userService.processUser("alice");userService.processUser("ab");} catch (Exception e) {logger.error("Processing failed", e);}logger.info("Application finished");}
}

6.4 运行结果分析

  1. 控制台输出(彩色):

    2025-08-01 09:00:00.123 [main] INFO  c.e.LoggingDemo - Application started
    2025-08-01 09:00:00.124 [main] DEBUG c.e.UserService - Processing user: alice
    2025-08-01 09:00:00.125 [main] INFO  c.e.UserService - Successfully processed user: alice
    2025-08-01 09:00:00.126 [main] DEBUG c.e.UserService - Processing user: ab
    2025-08-01 09:00:00.126 [main] ERROR c.e.UserService - Username 'ab' is too short
    2025-08-01 09:00:00.127 [main] ERROR c.e.LoggingDemo - Processing failed
    java.lang.IllegalArgumentException: Username too shortat com.example.UserService.processUser(UserService.java:18)...
    2025-08-01 09:00:00.128 [main] INFO  c.e.LoggingDemo - Application finished
    
  2. 日志文件

    • logs/myapp.log:包含所有DEBUG及以上日志。
    • logs/myapp-error.log:仅包含ERROR日志。
    • 当文件达到100MB或跨天时,生成新文件并压缩。

七、性能优化与最佳实践

7.1 性能优化技巧

  1. 使用异步日志

    • 显著降低日志记录的延迟。
    • 配置 AsyncAppender 或使用 AsyncLogger
  2. 避免不必要的字符串拼接

    • 始终使用 {} 占位符。

    • 在条件判断中检查日志级别:

      if (logger.isDebugEnabled()) {logger.debug("Complex object: " + expensiveToString()); // expensiveToString() 可能很耗时
      }
      // 更好的方式:让SLF4J内部判断
      logger.debug("Complex object: {}", () -> expensiveToString()); // Lambda延迟执行
      
  3. 合理设置日志级别

    • 生产环境避免 DEBUGTRACE
    • 使用MDC(Mapped Diagnostic Context)进行上下文追踪。
  4. 监控日志文件大小

    • 配置合理的滚动策略和保留策略,避免磁盘耗尽。

7.2 MDC(Mapped Diagnostic Context)

MDC允许在日志中添加上下文信息,如请求ID、用户ID,便于追踪分布式请求。

import org.slf4j.MDC;public class RequestHandler {private static final Logger logger = LoggerFactory.getLogger(RequestHandler.class);public void handleRequest(String requestId, String userId) {// 将上下文放入MDCMDC.put("requestId", requestId);MDC.put("userId", userId);try {logger.info("Handling request"); // 日志中会包含requestId和userId// ... 业务逻辑} finally {// 清理MDC,避免内存泄漏MDC.clear();}}
}

修改PatternLayout以包含MDC

<PatternLayout pattern="%d %p %c [%t] [%X{requestId} %X{userId}] %m%n"/>

输出

2025-08-01 09:15:30.456 INFO c.e.RequestHandler [main] [req-123 user-456] Handling request

7.3 最佳实践清单

  1. 使用SLF4J门面,避免直接依赖具体实现。
  2. Logger命名:使用 private static final Logger logger = LoggerFactory.getLogger(当前类.class);
  3. 日志级别选择
    • ERROR:系统错误,需要立即关注。
    • WARN:潜在问题,可能影响功能。
    • INFO:重要业务事件,如启动、关闭、关键操作。
    • DEBUG:调试信息,用于开发和问题排查。
    • TRACE:非常详细的调试信息。
  4. 记录异常:使用 logger.error("Message", exception),而非 logger.error("Message: " + exception.getMessage())
  5. 避免敏感信息:不要记录密码、密钥、身份证号等。
  6. 配置文件外置:将 log4j2.xml 放在 classpath 外,便于运维修改。
  7. 定期审查日志:确保日志内容有价值,避免“日志噪音”。

八、常见问题与解决方案

8.1 NoClassDefFoundError / ClassNotFoundException

问题:缺少必要的JAR包。

解决方案

  • 检查Maven依赖是否完整。
  • 确保SLF4J绑定库与Log4j版本兼容。
  • 使用 mvn dependency:tree 检查依赖冲突。

8.2 日志不输出

可能原因

  1. 配置文件未找到(不在classpath)。
  2. Logger级别设置过高(如OFF)。
  3. Appender配置错误(如路径不可写)。
  4. 存在多个SLF4J绑定,导致冲突。

排查步骤

  • 检查 status="DEBUG" 查看Log4j内部日志。
  • 确认 log4j2.xmlsrc/main/resources 目录。
  • 使用 LoggerFactory.getLogger("Test") 测试。

8.3 日志文件未滚动

原因

  • filePattern 配置错误。
  • Policies 未正确配置。
  • 磁盘空间不足或权限问题。

九、与其他框架集成

9.1 Spring Boot

Spring Boot默认使用 Logback,但可轻松切换到 Log4j 2

1. 排除Logback,引入Log4j 2
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
2. 配置文件
  • log4j2-spring.xml:Spring Boot推荐命名,支持Spring Profile。
  • application.properties 中配置:
    logging.config=classpath:log4j2-spring.xml
    

9.2 Web应用(Servlet)

web.xml 中配置Log4j 2的监听器,确保在应用启动时初始化:

<listener><listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
</listener><context-param><param-name>log4jConfiguration</param-name><param-value>/WEB-INF/log4j2.xml</param-value>
</context-param>

十、总结

Log4j 2.x 和 SLF4J 的组合为Java应用提供了强大、灵活、高性能的日志解决方案。

  • SLF4J 作为日志门面,实现了应用与日志实现的解耦,是“面向接口编程”原则的典范。
  • Log4j 2.x 作为日志实现,提供了丰富的功能、卓越的性能和高度的可配置性。

通过合理配置Appender、Layout、Level和过滤器,我们可以构建出满足各种需求的日志系统。结合MDC、异步日志、滚动策略等高级特性,能够有效支持生产环境的监控和运维。

记住,好的日志不是越多越好,而是要在正确的时间、以正确的格式、记录正确的内容。遵循最佳实践,定期审查和优化日志策略,你的应用将拥有一个可靠、高效的“黑匣子”。


附录:完整Maven依赖

<dependencies><!-- SLF4J API --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.36</version></dependency><!-- Log4j 2 API --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.19.0</version></dependency><!-- Log4j 2 Core --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.19.0</version></dependency><!-- SLF4J to Log4j 2 Bridge --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.19.0</version></dependency><!-- 可选:Log4j 2 Async Support (LMAX Disruptor) --><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.4</version></dependency>
</dependencies>

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sc-atac的基础知识(0)

sc-atac的基础知识 **fragment**是ATAC-seq实验中的一个重要概念&#xff0c;它指的是通过Tn5转座酶对DNA分子进行酶切&#xff0c;然后经由双端测序得到的序列。根据Tn5插入导致的偏移从read比对得到的位置推断出fragment的起始和结束位置。根据之前的报道&#xff0c;Tn5转座…

Python从入门到精通计划Day01: Python开发环境搭建指南:从零开始打造你的“数字厨房“

目录一、配置你的「魔杖」&#xff1a;Python 3.x安装1.1 跨平台安装指南1.2 验证你的「法力值」二、选择你的「魔法工坊」&#xff1a;IDE配置2.1 VS Code&#xff1a;轻量级实验室2.2 PyCharm&#xff1a;专业级法师塔三、施展第一个「魔咒」&#xff1a;Hello World3.1 基础…

MCP Agent 工程框架Dify初探

目录引言一、Dify是什么二、为什么使用Dify三、使用Dify要怎么做1、聊天助手2、Agent2.1 Function calling&#xff08;函数调用&#xff09;和 ReAct 两种推理模式的区别2.1.1 技术本质与工作流程对比2.1.2 优缺点对比2.1.3 适用场景与选择依据2.2 LangChain 的 Agent 实现原理…

无人机光伏巡检漏检率↓78%!陌讯多模态融合算法实战解析

原创声明本文为原创技术解析&#xff0c;核心技术参数与架构设计引用自《陌讯技术白皮书》&#xff0c;转载请注明来源。一、行业痛点&#xff1a;无人机光伏巡检的 "识别困境"光伏电站的大规模铺设推动了无人机巡检的普及&#xff0c;但实际作业中仍面临三大技术瓶颈…

机动车占道识别准确率提升 29%:陌讯动态轮廓感知算法实战解析

原创声明本文为原创技术解析&#xff0c;核心技术参数与架构设计引用自《陌讯技术白皮书》&#xff0c;禁止未经授权的转载与改编。一、行业痛点&#xff1a;机动车占道治理的技术瓶颈城市交通监控中&#xff0c;机动车占用应急车道、公交车道等违规行为已成为影响通行效率与交…

UNet改进(29):记忆增强注意力机制在UNet中的创新应用-原理、实现与性能提升

记忆增强注意力机制概述 记忆增强注意力是一种结合了外部记忆模块的注意力机制,它使神经网络能够存储和检索长期知识,而不仅仅是依赖当前的输入特征。这种机制特别适合需要保持长期依赖关系的任务,如医学图像分割,其中模型需要记住不同样本中出现的常见模式。 核心组件 记…

使用Python开发Ditto剪贴板数据导出工具

前言在日常工作中&#xff0c;我们经常需要处理大量的剪贴板数据。Ditto作为一款优秀的剪贴板管理软件&#xff0c;帮助我们保存了丰富的历史记录。但有时我们需要将这些数据导出进行进一步分析或备份&#xff0c;而Ditto本身并没有提供直观的批量导出功能。C:\pythoncode\new\…

【人工智能】提示词设计原则:简洁性、明确性、具体性如何平衡?

提示词设计原则&#xff1a;简洁性、明确性、具体性如何平衡&#xff1f;1. 提示词设计三大原则的核心内涵1.1 简洁性1.1.1 定义用最少的文字传递核心信息&#xff0c;避免冗余和不必要的描述。比如 “写 3 个春天的成语” 比 “我想让你写出来 3 个和春天有关系的成语词语” 更…

JS的作用域

文章目录一、为什么需要作用域&#xff1f;二、什么是 JS 作用域&#xff1f;2.1 什么是词法作用域和动态作用域&#xff1f;1. 词法作用域&#xff08;Lexical Scpoe&#xff09;2. 动态作用域2.2 JS 的作用域2.3 JS 作用域的分类1. 全局作用域2. 模块作用域3. 函数作用域4. 块…

OLTP,OLAP,HTAP是什么,数据库该怎么选

目录 OLTP&#xff08;Online Transaction Processing&#xff09;联机事务处理 OLAP&#xff08;Online Analytical Processing&#xff09;联机分析处理 非实时OLAP 实时OLAP HTAP&#xff08;Hybrid Transactional/Analytical Processing&#xff09; OLAP 和 OLTP 数…

【前端】CSS Flexbox布局示例介绍

CSS Flexbox&#xff08;弹性盒子&#xff09;简介 Flexbox 是一种一维布局模型&#xff0c;用于高效处理元素在容器内的空间分配、对齐和排序。它通过父容器&#xff08;flex container&#xff09;和子元素&#xff08;flex items&#xff09;的配合实现灵活响应式布局。核心…

Vue3核心语法基础

一、为什么要学 Composition API&#xff1f;在以前我们写代码用Vue2写&#xff1a;export default {data() {return { count: 0, msg: hello }},methods: {add() { this.count }},computed: {double() { return this.count * 2 }} }很明显 一个功能被拆成三块&#xff1a;data…

FSMC的配置和应用

一、FSMC 简介与工作原理FSMC&#xff08;Flexible Static Memory Controller&#xff09;是 STM32 微控制器中用于与外部静态存储器&#xff08;如 SRAM、PSRAM、NOR Flash、LCD 等&#xff09;进行通信的一个外设模块。1、支持的设备类型&#xff1a;SRAM / PSRAMNOR FlashNA…

Linux I/O 系统调用完整对比分析

Linux I/O 系统调用完整对比分析 1. 概述 Linux 提供了丰富的 I/O 系统调用&#xff0c;每种都有其特定的用途和优势。本文将详细分析这些系统调用的特点、使用场景和性能特征。 2. 系统调用详细对比 2.1 基本读写函数 pread/pwrite #include <unistd.h>// 位置指定…

TiDB集群部署

架构&#xff1a; tidb–3台&#xff0c;pd–3台&#xff0c;tikv–3台 8c16g200g 1x2.2x.2x7.124 1x2.2x.2x7.148 1x2.2x.2x7.87 1x2.2x.2x7.93 1x2.2x.2x7.127 1x2.2x.2x7.104 pd-3台 4c8g100g 1x2.2x.2x7.143 1x2.2x.2x7.132 1x2.2x.2x7.91 1、下载安装包 #注&#xff1a;我…

C#中对于List的多种排序方式

在 C# 中给 List<AI> 排序&#xff0c;只要 明确排序规则&#xff08;比如按某个字段、某几个字段、或外部规则&#xff09;&#xff0c;就能用下面几种常见写法。下面全部基于这个示例类&#xff1a;public class AI {public int country; // 国家编号public int pr…

Spring框架中Bean的生命周期:源码解析与最佳实践

第1章&#xff1a;Spring Bean生命周期概述1.1 什么是Spring Bean生命周期&#xff1f;定义&#xff1a;Spring Bean生命周期是指从Bean的创建、初始化、使用到销毁的完整过程&#xff0c;由Spring容器严格管理 。核心思想是Spring容器通过IoC&#xff08;控制反转&#xff09;…

【51单片机6位数码管密码锁】2022-10-15

缘由六位密码器设计连接LED-嵌入式-CSDN问答 矩阵51单片机密码锁,回复:https://bbs.csdn.net/topics/392713242_智者知已应修善业的博客-CSDN博客 #include "REG52.h" unsigned char code smgduan[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x…

‌我的第一个开源项目:跃动的心

还是一个编程初学者时&#xff0c;我怀着激动的心情完成了人生第一个开源项目——一个用HTML5 Canvas制作的动态跳动爱心效果。这个项目虽然简单&#xff0c;却让我深刻体会到了开源分享的快乐和技术创造的魅力。 壹、项目灵感 这个项目的灵感来源于浏览网页时&#xff0c;被各…

技术演进中的开发沉思-53 DELPHI VCL系列:windows的消息(下):TApplication窗体

今天我们梳理下关于TApplication的窗体消息下半部分的内容。前面也说过&#xff0c;在 Delphi 的世界里&#xff0c;TApplication 就像一位经验丰富的总工程师&#xff0c;而主窗体则是它倾注心血打造的核心建筑。如果你第一次在实验室里敲出 Delphi 代码时&#xff0c;屏幕上弹…