SpringBoot的5种日志输出规范策略

在企业级应用开发中,合理规范的日志记录是系统稳定运行、问题排查和性能优化的关键保障。

SpringBoot作为流行的Java开发框架,提供了强大而灵活的日志支持,但如何建立统一、高效的日志输出规范却是许多团队面临的挑战。

本文将介绍SpringBoot中5种日志输出规范策略。

一、统一日志格式配置策略

1.1 基本原理

统一的日志格式是团队协作的基础,可以提高日志的可读性和可分析性。

SpringBoot允许开发者自定义日志输出格式,包括时间戳、日志级别、线程信息、类名和消息内容等。

1.2 实现方式

1.2.1 配置文件方式

application.propertiesapplication.yml中定义日志格式:

# application.properties
# 控制台日志格式
logging.pattern.console=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}# 文件日志格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}

YAML格式配置:

logging:pattern:console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"file: "%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"
1.2.2 自定义Logback配置

对于更复杂的配置,可以使用logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration><property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/><property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>${CONSOLE_LOG_PATTERN}</pattern><charset>UTF-8</charset></encoder></appender><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/application.log</file><encoder><pattern>${FILE_LOG_PATTERN}</pattern><charset>UTF-8</charset></encoder><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>logs/archived/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern><maxFileSize>10MB</maxFileSize><maxHistory>30</maxHistory><totalSizeCap>3GB</totalSizeCap></rollingPolicy></appender><root level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="FILE" /></root>
</configuration>
1.2.3 JSON格式日志配置

对于需要集中式日志分析的系统,配置JSON格式日志更有利于日志处理:

<dependency><groupId>net.logstash.logback</groupId><artifactId>logstash-logback-encoder</artifactId><version>7.2</version>
</dependency>
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/application.json</file><encoder class="net.logstash.logback.encoder.LogstashEncoder"><includeMdcKeyName>requestId</includeMdcKeyName><includeMdcKeyName>userId</includeMdcKeyName><customFields>{"application":"my-service","environment":"${ENVIRONMENT:-development}"}</customFields></encoder><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>logs/archived/application.%d{yyyy-MM-dd}.%i.json</fileNamePattern><maxFileSize>10MB</maxFileSize><maxHistory>30</maxHistory><totalSizeCap>3GB</totalSizeCap></rollingPolicy>
</appender>

1.3 最佳实践

  1. 环境区分:为不同环境配置不同的日志格式(开发环境可读性高,生产环境机器可解析)
<springProfile name="dev"><!-- 开发环境配置 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{15}) - %msg%n</pattern></encoder></appender>
</springProfile>
<springProfile name="prod"><!-- 生产环境配置 --><appender name="JSON_CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder class="net.logstash.logback.encoder.LogstashEncoder"/></appender>
</springProfile>
  1. 添加关键信息:确保日志中包含足够的上下文信息
%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] [%X{userId}] %-5level [%thread] %logger{36} - %msg%n
  1. 注意敏感信息:避免记录密码、令牌等敏感信息,必要时进行脱敏处理

二、分级日志策略

2.1 基本原理

合理使用日志级别可以帮助区分不同重要程度的信息,便于问题定位和系统监控。

SpringBoot支持标准的日志级别:TRACE、DEBUG、INFO、WARN、ERROR。

2.2 实现方式

2.2.1 配置不同包的日志级别
# 全局日志级别
logging.level.root=INFO# 特定包的日志级别
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
logging.level.com.mycompany.app=DEBUG
2.2.2 基于环境的日志级别配置
# application.yml
spring:profiles:active: dev---
spring:config:activate:on-profile: dev
logging:level:root: INFOcom.mycompany.app: DEBUGorg.springframework: INFO---
spring:config:activate:on-profile: prod
logging:level:root: WARNcom.mycompany.app: INFOorg.springframework: WARN
2.2.3 编程式日志级别管理
@RestController
@RequestMapping("/api/logs")
public class LoggingController {@Autowiredprivate LoggingSystem loggingSystem;@PutMapping("/level/{package}/{level}")public void changeLogLevel(@PathVariable("package") String packageName,@PathVariable("level") String level) {LogLevel logLevel = LogLevel.valueOf(level.toUpperCase());loggingSystem.setLogLevel(packageName, logLevel);}
}

2.3 日志级别使用规范

建立清晰的日志级别使用规范对团队协作至关重要:

  1. ERROR:系统错误、应用崩溃、服务不可用等严重问题
try {// 业务操作
} catch (Exception e) {log.error("Failed to process payment for order: {}", orderId, e);throw new PaymentProcessingException("Payment processing failed", e);
}
  1. WARN:不影响当前功能但需要注意的问题
if (retryCount > maxRetries / 2) {log.warn("High number of retries detected for operation: {}, current retry: {}/{}", operationType, retryCount, maxRetries);
}
  1. INFO:重要业务流程、系统状态变更等信息
log.info("Order {} has been successfully processed with {} items", order.getId(), order.getItems().size());
  1. DEBUG:调试信息,详细的处理流程
log.debug("Processing product with ID: {}, name: {}, category: {}", product.getId(), product.getName(), product.getCategory());
  1. TRACE:最详细的追踪信息,一般用于框架内部
log.trace("Method execution path: class={}, method={}, params={}", className, methodName, Arrays.toString(args));

2.4 最佳实践

  1. 默认使用INFO级别:生产环境默认使用INFO级别,开发环境可使用DEBUG
  2. 合理划分包结构:按功能或模块划分包,便于精细控制日志级别
  3. 避免日志爆炸:谨慎使用DEBUG和TRACE级别,避免产生大量无用日志
  4. 条件日志:使用条件判断减少不必要的字符串拼接开销
// 推荐方式
if (log.isDebugEnabled()) {log.debug("Complex calculation result: {}", calculateComplexResult());
}// 避免这样使用
log.debug("Complex calculation result: " + calculateComplexResult());

三、日志切面实现策略

3.1 基本原理

使用AOP(面向切面编程)可以集中处理日志记录,避免在每个方法中手动编写重复的日志代码。尤其适合API调用日志、方法执行时间统计等场景。

3.2 实现方式

3.2.1 基础日志切面
@Aspect
@Component
@Slf4j
public class LoggingAspect {@Pointcut("execution(* com.mycompany.app.service.*.*(..))")public void serviceLayer() {}@Around("serviceLayer()")public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {String className = joinPoint.getSignature().getDeclaringTypeName();String methodName = joinPoint.getSignature().getName();log.info("Executing: {}.{}", className, methodName);long startTime = System.currentTimeMillis();try {Object result = joinPoint.proceed();long executionTime = System.currentTimeMillis() - startTime;log.info("Executed: {}.{} in {} ms", className, methodName, executionTime);return result;} catch (Exception e) {log.error("Exception in {}.{}: {}", className, methodName, e.getMessage(), e);throw e;}}
}
3.2.2 API请求响应日志切面
@Aspect
@Component
@Slf4j
public class ApiLoggingAspect {@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) || " +"@annotation(org.springframework.web.bind.annotation.GetMapping) || " +"@annotation(org.springframework.web.bind.annotation.PostMapping) || " +"@annotation(org.springframework.web.bind.annotation.PutMapping) || " +"@annotation(org.springframework.web.bind.annotation.DeleteMapping)")public void apiMethods() {}@Around("apiMethods()")public Object logApiCall(ProceedingJoinPoint joinPoint) throws Throwable {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();String requestURI = request.getRequestURI();String httpMethod = request.getMethod();String clientIP = request.getRemoteAddr();log.info("API Request - Method: {} URI: {} Client: {}", httpMethod, requestURI, clientIP);long startTime = System.currentTimeMillis();try {Object result = joinPoint.proceed();long duration = System.currentTimeMillis() - startTime;log.info("API Response - Method: {} URI: {} Duration: {} ms Status: SUCCESS", httpMethod, requestURI, duration);return result;} catch (Exception e) {long duration = System.currentTimeMillis() - startTime;log.error("API Response - Method: {} URI: {} Duration: {} ms Status: ERROR Message: {}", httpMethod, requestURI, duration, e.getMessage(), e);throw e;}}
}
3.2.3 自定义注解实现有选择的日志记录
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface LogExecutionTime {String description() default "";
}
@Aspect
@Component
@Slf4j
public class CustomLogAspect {@Around("@annotation(logExecutionTime)")public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {String description = logExecutionTime.description();String methodName = joinPoint.getSignature().getName();log.info("Starting {} - {}", methodName, description);long startTime = System.currentTimeMillis();try {Object result = joinPoint.proceed();long executionTime = System.currentTimeMillis() - startTime;log.info("Completed {} - {} in {} ms", methodName, description, executionTime);return result;} catch (Exception e) {long executionTime = System.currentTimeMillis() - startTime;log.error("Failed {} - {} after {} ms: {}", methodName, description, executionTime, e.getMessage(), e);throw e;}}
}

使用示例:

@Service
public class OrderService {@LogExecutionTime(description = "Process order payment")public PaymentResult processPayment(Order order) {// 处理支付逻辑}
}

3.3 最佳实践

  1. 合理定义切点:避免过于宽泛的切点定义,防止产生过多日志
  2. 注意性能影响:记录详细参数和结果可能带来性能开销,需权衡取舍
  3. 异常处理:确保日志切面本身不会抛出异常,影响主业务流程
  4. 避免敏感信息:敏感数据进行脱敏处理后再记录
// 敏感信息脱敏示例
private String maskCardNumber(String cardNumber) {if (cardNumber == null || cardNumber.length() < 8) {return "***";}return "******" + cardNumber.substring(cardNumber.length() - 4);
}

四、MDC上下文跟踪策略

4.1 基本原理

MDC (Mapped Diagnostic Context) 是一种用于存储请求级别上下文信息的工具,它可以在日志框架中保存和传递这些信息,特别适合分布式系统中的请求跟踪。

4.2 实现方式

4.2.1 配置MDC过滤器
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MdcLoggingFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {try {// 生成唯一请求IDString requestId = UUID.randomUUID().toString().replace("-", "");MDC.put("requestId", requestId);// 添加用户信息(如果有)Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication != null && authentication.isAuthenticated()) {MDC.put("userId", authentication.getName());}// 添加请求信息MDC.put("clientIP", request.getRemoteAddr());MDC.put("userAgent", request.getHeader("User-Agent"));MDC.put("httpMethod", request.getMethod());MDC.put("requestURI", request.getRequestURI());// 设置响应头,便于客户端跟踪response.setHeader("X-Request-ID", requestId);filterChain.doFilter(request, response);} finally {// 清理MDC上下文,防止内存泄漏MDC.clear();}}
}
4.2.2 日志格式中包含MDC信息
<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] [%X{userId}] %-5level [%thread] %logger{36} - %msg%n"/>
4.2.3 分布式追踪集成

与Spring Cloud Sleuth和Zipkin集成,实现全链路追踪:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
spring.application.name=my-service
spring.sleuth.sampler.probability=1.0
spring.zipkin.base-url=http://localhost:9411
4.2.4 手动管理MDC上下文
@Service
public class BackgroundJobService {private static final Logger log = LoggerFactory.getLogger(BackgroundJobService.class);@Asyncpublic CompletableFuture<Void> processJob(String jobId, Map<String, String> context) {// 保存原有MDC上下文Map<String, String> previousContext = MDC.getCopyOfContextMap();try {// 设置新的MDC上下文MDC.put("jobId", jobId);if (context != null) {context.forEach(MDC::put);}log.info("Starting background job processing");// 执行业务逻辑// ...log.info("Completed background job processing");return CompletableFuture.completedFuture(null);} finally {// 恢复原有MDC上下文或清除if (previousContext != null) {MDC.setContextMap(previousContext);} else {MDC.clear();}}}
}

4.3 最佳实践

  1. 唯一请求标识:为每个请求生成唯一ID,便于追踪完整请求链路
  2. 传递MDC上下文:在异步处理和线程池中正确传递MDC上下文
  3. 合理选择MDC信息:记录有价值的上下文信息,但避免过多信息造成日志膨胀
  4. 与分布式追踪结合:与Sleuth、Zipkin等工具结合,提供完整的分布式追踪能力
// 自定义线程池配置,传递MDC上下文
@Configuration
public class AsyncConfig implements AsyncConfigurer {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.setThreadNamePrefix("MyAsync-");// 包装原始Executor,传递MDC上下文executor.setTaskDecorator(runnable -> {Map<String, String> contextMap = MDC.getCopyOfContextMap();return () -> {try {if (contextMap != null) {MDC.setContextMap(contextMap);}runnable.run();} finally {MDC.clear();}};});executor.initialize();return executor;}
}

五、异步日志策略

5.1 基本原理

在高性能系统中,同步记录日志可能成为性能瓶颈,特别是在I/O性能受限的环境下。

异步日志通过将日志操作从主线程中分离,可以显著提升系统性能。

5.2 实现方式

5.2.1 Logback异步配置
<configuration><!-- 定义日志内容和格式 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 配置详情... --></appender><!-- 异步appender --><appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="FILE" /><queueSize>512</queueSize><discardingThreshold>0</discardingThreshold><includeCallerData>false</includeCallerData><neverBlock>false</neverBlock></appender><root level="INFO"><appender-ref ref="ASYNC" /></root>
</configuration>
5.2.2 Log4j2异步配置

添加依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.4</version>
</dependency>

配置Log4j2:

<Configuration status="WARN"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console><RollingFile name="RollingFile" fileName="logs/app.log"filePattern="logs/app-%d{MM-dd-yyyy}-%i.log.gz"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/><Policies><TimeBasedTriggeringPolicy /><SizeBasedTriggeringPolicy size="10 MB"/></Policies><DefaultRolloverStrategy max="20"/></RollingFile><!-- 异步Appender --><Async name="AsyncFile"><AppenderRef ref="RollingFile"/><BufferSize>1024</BufferSize></Async></Appenders><Loggers><Root level="info"><AppenderRef ref="Console"/><AppenderRef ref="AsyncFile"/></Root></Loggers>
</Configuration>
5.2.3 性能优化配置

针对Log4j2进行更高级的性能优化:

<Configuration status="WARN" packages="com.mycompany.logging"><Properties><Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property></Properties><Appenders><!-- 使用MappedFile提高I/O性能 --><RollingRandomAccessFile name="RollingFile" fileName="logs/app.log"filePattern="logs/app-%d{MM-dd-yyyy}-%i.log.gz"><PatternLayout pattern="${LOG_PATTERN}"/><Policies><TimeBasedTriggeringPolicy /><SizeBasedTriggeringPolicy size="25 MB"/></Policies><DefaultRolloverStrategy max="20"/></RollingRandomAccessFile><!-- 使用更高性能的Async配置 --><Async name="AsyncFile" bufferSize="2048"><AppenderRef ref="RollingFile"/><DisruptorBlockingQueue /></Async></Appenders><Loggers><!-- 降低某些高频日志的级别 --><Logger name="org.hibernate.SQL" level="debug" additivity="false"><AppenderRef ref="AsyncFile" level="debug"/></Logger><Root level="info"><AppenderRef ref="AsyncFile"/></Root></Loggers>
</Configuration>
5.2.4 自定义异步日志记录器

对于特殊需求,可以实现自定义的异步日志记录器:

@Component
public class AsyncLogger {private static final Logger log = LoggerFactory.getLogger(AsyncLogger.class);private final ExecutorService logExecutor;public AsyncLogger() {this.logExecutor = Executors.newSingleThreadExecutor(r -> {Thread thread = new Thread(r, "async-logger");thread.setDaemon(true);return thread;});// 确保应用关闭时处理完所有日志Runtime.getRuntime().addShutdownHook(new Thread(() -> {logExecutor.shutdown();try {if (!logExecutor.awaitTermination(5, TimeUnit.SECONDS)) {log.warn("AsyncLogger executor did not terminate in the expected time.");}} catch (InterruptedException e) {Thread.currentThread().interrupt();}}));}public void info(String format, Object... arguments) {logExecutor.submit(() -> log.info(format, arguments));}public void warn(String format, Object... arguments) {logExecutor.submit(() -> log.warn(format, arguments));}public void error(String format, Object... arguments) {Throwable throwable = extractThrowable(arguments);if (throwable != null) {logExecutor.submit(() -> log.error(format, arguments));} else {logExecutor.submit(() -> log.error(format, arguments));}}private Throwable extractThrowable(Object[] arguments) {if (arguments != null && arguments.length > 0) {Object lastArg = arguments[arguments.length - 1];if (lastArg instanceof Throwable) {return (Throwable) lastArg;}}return null;}
}

5.3 最佳实践

  1. 队列大小设置:根据系统吞吐量和内存情况设置合理的队列大小
  2. 丢弃策略配置:在高负载情况下,可以考虑丢弃低优先级的日志
<AsyncAppender name="ASYNC" queueSize="512" discardingThreshold="20"><!-- 当队列剩余容量低于20%时,会丢弃TRACE, DEBUG和INFO级别的日志 -->
</AsyncAppender>
  1. 异步日志的注意事项

    • 异步日志可能导致异常堆栈信息不完整
    • 系统崩溃时可能丢失最后一批日志
    • 需要权衡性能和日志完整性
  2. 合理使用同步与异步

    • 关键操作日志(如金融交易)使用同步记录确保可靠性
    • 高频但不关键的日志(如访问日志)使用异步记录提高性能
// 同步记录关键业务日志
log.info("Transaction completed: id={}, amount={}, status={}", transaction.getId(), transaction.getAmount(), transaction.getStatus());// 异步记录高频统计日志
asyncLogger.info("API usage stats: endpoint={}, count={}, avgResponseTime={}ms", endpoint, requestCount, avgResponseTime);

另外,性能要求较高的应用推荐使用log4j2的异步模式,性能远高于logback。

六、总结

这些策略不是相互排斥的,而是可以结合使用,共同构建完整的日志体系。

在实际应用中,应根据项目规模、团队情况和业务需求,选择合适的日志规范策略组合。

好的日志实践不仅能帮助开发者更快地定位和解决问题,还能为系统性能优化和安全审计提供重要依据。

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

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

相关文章

Python Cookbook-7.11 在 PostgreSQL 中储存 BLOB

任务 需要将 BLOB 存入一个 PostgreSQL 数据库。 解决方案 PostgreSQL7.2 以及更新的版本支持大对象,而psycopg 模块提供了二进制转义函数: import psycopg,cPickle #连接到数据库,用你的本机来测试数据库,并获得游标 connection = psycopg.connect("dbname = test…

Android端口转发

如上图所示&#xff0c;有一个Android设备&#xff0c;Android设备里面有主板&#xff0c;主板上有网络接口和Wi-Fi&#xff0c;网络接口通过网线连接了一个网络摄像头&#xff0c;这就跟电脑一样&#xff0c;电脑即可以通过网线接入一个网络&#xff0c;也可以同时用Wi-Fi接入…

Unity基础-协程

Unity基础-协程 四、协程 概述 协程&#xff08;Coroutine&#xff09;&#xff0c;本质上并不是多线程&#xff0c;而是在当前线程中将代码分时执行&#xff0c;不卡主线程。可以理解为&#xff0c;协程会把可能使主线程卡顿的程序分时分布进行。 协程通常用来&#xff1a;…

UniApp组件封装,2025年最新HarmonyOS鸿蒙模块化开发项目式教程

一、环境配置与前置条件 ‌开发工具要求‌ HBuilderX 4.64&#xff08;鸿蒙插件已预装&#xff09;DevEco Studio 5.0.3.400&#xff08;真机调试必备&#xff09;鸿蒙离线SDK&#xff08;通过HBuilderX导入&#xff0c;每个项目独立配置&#xff09; ‌项目初始化 # 创建Vu…

C++ 精简知识点

目录 一、核心语法 1.指针VS引用 2. 类与对象&#xff08;必写代码&#xff09; 3. 继承与多态&#xff08;必写代码&#xff09; 4. 模板&#xff08;必写代码&#xff09; 5.智能指针 6. 异常处理&#xff08;必写结构&#xff09; 二、简答题速记 三、考试应急策略 一…

7.Vue的compute计算属性

3.8. 【computed】 作用&#xff1a;根据已有数据计算出新数据&#xff08;和Vue2中的computed作用一致&#xff09;。 <template><div class"person">姓&#xff1a;<input type"text" v-model"firstName"> <br>名&am…

在VSCode中借助AI丰富C++Qt应用程序

随着国内外各类自动化编程助手的普及&#xff0c;作为传统桌面C开发者&#xff0c;也要及时地用上这样强大的工具。考虑到网速问题&#xff0c;国外的服务时断时续&#xff0c;还是倾向于使用一些国产的大语言模型助手。我们今天就来看看在VSCode下使用大语言模型辅助Qt开发。 …

Java八股文——JVM「内存模型篇」

JVM的内存模型介绍一下 面试官您好&#xff0c;您问的“JVM内存模型”&#xff0c;这是一个非常核心的问题。在Java技术体系中&#xff0c;这个术语通常可能指代两个不同的概念&#xff1a;一个是JVM的运行时数据区&#xff0c;另一个是Java内存模型&#xff08;JMM&#xff0…

RabbitMQ 高可用与可靠性保障实现

RabbitMQ 高可用与可靠性保障实现详解 一、高可用架构设计1.1 集群部署模式1.2 镜像队列&#xff08;Mirrored Queue&#xff09; 二、可靠性保障机制2.1 消息持久化2.2 确认机制&#xff08;Confirm & Ack&#xff09;2.3 死信队列&#xff08;DLX&#xff09; 三、容灾与…

12.7Swing控件6 JList

在 Java Swing 中&#xff0c;列表框&#xff08;JList&#xff09;是用于显示一组选项的组件&#xff0c;用户可以从中选择一个或多个项目。以下是关于 Swing 列表框的详细介绍&#xff1a; 1. 基本概念与用途 作用&#xff1a;以垂直列表形式展示选项&#xff0c;支持单选或…

C++: condition_variable: wait_for -> unlock_wait_for_lock?

作为C++的初学者,面临的一个很大的问题,就是很多的概念并不是可以通过名称直观的预知它要完成的细节,比如这里的condition_variable的wait_for。C++的设计意图好像是,我告诉你这样用,你只要这样做就行,又简单还实用!而且需要记住的规则量又大的惊人。最后看起来,更像是…

HTML版英语学习系统

HTML版英语学习系统 这是一个完全免费、无需安装、功能完整的英语学习工具&#xff0c;使用HTML CSS JavaScript实现。 功能 文本朗读练习 - 输入英文文章&#xff0c;系统朗读帮助练习听力和发音&#xff0c;适合跟读练习&#xff0c;模仿学习&#xff1b;实时词典查询 - 双…

【JUC面试篇】Java并发编程高频八股——线程与多线程

目录 1. 什么是进程和线程&#xff1f;有什么区别和联系&#xff1f; 2. Java的线程和操作系统的线程有什么区别&#xff1f; 3. 线程的创建方式有哪些? 4. 如何启动和停止线程&#xff1f; 5. Java线程的状态模型&#xff08;有哪些状态&#xff09;&#xff1f; 6. 调用…

LSTM-SVM多变量时序预测(Matlab完整源码和数据)

LSTM-SVM多变量时序预测&#xff08;Matlab完整源码和数据&#xff09; 目录 LSTM-SVM多变量时序预测&#xff08;Matlab完整源码和数据&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 代码主要功能 该代码实现了一个LSTM-SVM多变量时序预测模型&#xff0c…

ES6——数组扩展之Set数组

在ES6&#xff08;ECMAScript 2015&#xff09;中&#xff0c;JavaScript的Set对象提供了一种存储任何值唯一性的方式&#xff0c;类似于数组但又不需要索引访问。这对于需要确保元素唯一性的场景非常有用。Set对象本身并不直接提供数组那样的方法来操作数据&#xff08;例如ma…

日志收集工具-logstash

提示&#xff1a;Windows 环境下 安装部署 logstash 采集日志文件 文章目录 一、下载二、解压部署三、常用插件四、常用配置 Logstash 服务器数据处理管道&#xff0c;能够从多个来源采集数据&#xff0c;转换数据&#xff0c;然后将数据发送到您最喜欢的存储库中。Logstash 没…

6个月Python学习计划 Day 21 - Python 学习前三周回顾总结

✅ 第一周&#xff1a;基础入门与流程控制&#xff08;Day 1 - 7&#xff09; “打地基”的一周&#xff0c;我们走完了从变量、输入输出、判断、循环到第一个小型系统的完整链路。 &#x1f4d8; 学习重点&#xff1a; Python 基础语法&#xff1a;变量类型、字符串格式化、注…

Spring Boot SQL数据库功能详解

Spring Boot自动配置与数据源管理 数据源自动配置机制 当在Spring Boot项目中添加数据库驱动依赖&#xff08;如org.postgresql:postgresql&#xff09;后&#xff0c;应用启动时自动配置系统会尝试创建DataSource实现。开发者只需提供基础连接信息&#xff1a; 数据库URL格…

java每日精进 6.11【消息队列】

1.内存级Spring_Event 1.1 控制器层&#xff1a;StringTextController /*** 字符串文本管理控制器* 提供通过消息队列异步获取文本信息的接口*/ RestController RequestMapping("/api/string-text") public class StringTextController {Resourceprivate StringTex…

【凌智视觉模块】rv1106 部署 ppocrv4 检测模型 rknn 推理

PP-OCRv4 文本框检测 1. 模型介绍 如有需要可以前往我们的仓库进行查看 凌智视觉模块 PP-OCRv4在PP-OCRv3的基础上进一步升级。整体的框架图保持了与PP-OCRv3相同的pipeline&#xff0c;针对检测模型和识别模型进行了数据、网络结构、训练策略等多个模块的优化。 从算法改…