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
繁體地址,請注明出處:http://hk.pswp.cn/diannao/86723.shtml
英文地址,請注明出處:http://en.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;針對檢測模型和識別模型進行了數據、網絡結構、訓練策略等多個模塊的優化。 從算法改…