最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中構建生產級日志系統(tǒng)的優(yōu)雅指南

 更新時間:2026年04月16日 09:23:22   作者:悟空碼字  
本文介紹了構建生產級日志系統(tǒng)的必要性及詳細步驟,包括需求描述,日志工具類封裝等內容,并給出了最佳實踐和檢查清單,希望對大家有所幫助

一、需求描述

在實際開發(fā)中,日志系統(tǒng)需要滿足以下需求:

  • 區(qū)分日志級別:DEBUG/INFO/WARN/ERROR 各司其職
  • 性能友好:避免日志序列化開銷,支持異步輸出
  • 鏈路追蹤:一次請求全鏈路可追蹤(RequestId)
  • 敏感信息脫敏:手機號、身份證等自動脫敏
  • 日志分類:業(yè)務日志、錯誤日志、慢SQL日志分開存儲
  • 輸出規(guī)范:JSON格式,便于ELK采集分析
  • 開發(fā)/生產環(huán)境差異化:開發(fā)環(huán)境輸出控制臺,生產環(huán)境輸出文件

二、詳細步驟與代碼實現

1. 添加依賴

<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 性能優(yōu)化:異步日志需要disruptor -->
    <dependency>
        <groupId>com.lmax</groupId>
        <artifactId>disruptor</artifactId>
        <version>3.4.4</version>
    </dependency>
    <!-- 鏈路追蹤 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-sleuth</artifactId>
        <version>3.1.5</version>
    </dependency>
    <!-- 簡化代碼:lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

2. 配置文件(application.yml)

# application.yml
spring:
  application:
    name: demo-service
  # 鏈路追蹤配置
  sleuth:
    web:
      enabled: true
    sampler:
      probability: 1.0  # 生產環(huán)境建議0.1
# 日志配置
logging:
  # 日志文件路徑
  file:
    path: ./logs
    name: ${logging.file.path}/${spring.application.name}.log
  # 日志級別
  level:
    root: INFO
    com.example: DEBUG
    org.springframework.web: INFO
    org.hibernate: WARN
  # 日志格式
  pattern:
    console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx"
    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%t] %-40.40logger{39} : %m%n%wEx"
# 自定義日志配置
log:
  # 敏感字段列表
  sensitive-fields:
    - password
    - oldPassword
    - newPassword
    - idCard
    - phone
    - bankCard
    - token
    - secret

3. Logback配置(logback-spring.xml)

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
    <!-- 引入Spring環(huán)境配置 -->
    <springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="app"/>
    <springProperty scope="context" name="LOG_PATH" source="logging.file.path" defaultValue="./logs"/>
    <!-- 彩色日志依賴 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <!-- 日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" 
              value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx"/>
    <property name="FILE_LOG_PATTERN" 
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%t] %-40.40logger{39} : %m%n%wEx"/>
    <!-- JSON格式(用于生產環(huán)境ELK) -->
    <property name="JSON_LOG_PATTERN" 
              value='{"timestamp":"%d{yyyy-MM-dd HH:mm:ss.SSS}","level":"%p","app":"${APP_NAME}","traceId":"%X{traceId}","thread":"%t","logger":"%logger","message":"%m","exception":"%wEx"}%n'/>
    <!-- 控制臺輸出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!-- 異步控制臺輸出(性能優(yōu)化) -->
    <appender name="ASYNC_CONSOLE" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <queueSize>1024</queueSize>
        <appender-ref ref="CONSOLE"/>
    </appender>
    <!-- 普通日志文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APP_NAME}.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!-- 錯誤日志單獨文件 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${APP_NAME}-error.log</file>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${APP_NAME}-error.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>90</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!-- 業(yè)務日志文件 -->
    <appender name="BIZ_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/biz.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/biz.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- 異步文件輸出(性能優(yōu)化) -->
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>2048</queueSize>
        <discardingThreshold>0</discardingThreshold>
        <includeCallerData>true</includeCallerData>
        <appender-ref ref="FILE"/>
    </appender>
    <appender name="ASYNC_ERROR_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>1024</queueSize>
        <appender-ref ref="ERROR_FILE"/>
    </appender>
    <appender name="ASYNC_BIZ_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>1024</queueSize>
        <appender-ref ref="BIZ_FILE"/>
    </appender>
    <!-- 業(yè)務日志 Logger -->
    <logger name="BIZ_LOGGER" level="INFO" additivity="false">
        <appender-ref ref="ASYNC_BIZ_FILE"/>
    </logger>
    <!-- Root Logger -->
    <root level="INFO">
        <appender-ref ref="ASYNC_CONSOLE"/>
        <appender-ref ref="ASYNC_FILE"/>
        <appender-ref ref="ASYNC_ERROR_FILE"/>
    </root>
</configuration>

4. 日志工具類封裝

package com.example.log.util;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

/**
 * 日志工具類
 */
@Slf4j
@Component
public class LogUtil {
    
    // 業(yè)務日志專用Logger
    private static final Logger BIZ_LOGGER = LoggerFactory.getLogger("BIZ_LOGGER");
    
    /**
     * 獲取當前請求的TraceId
     */
    public static String getTraceId() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                String traceId = request.getHeader("X-Trace-Id");
                if (traceId == null || traceId.isEmpty()) {
                    traceId = UUID.randomUUID().toString().replace("-", "");
                }
                return traceId;
            }
        } catch (Exception e) {
            log.warn("獲取TraceId失敗", e);
        }
        return UUID.randomUUID().toString().replace("-", "");
    }
    
    /**
     * 業(yè)務日志(關鍵操作記錄)
     */
    public static void bizLog(String operation, String userId, Object... params) {
        String traceId = getTraceId();
        String message = String.format("[BIZ][%s][%s][%s] params: %s", 
            traceId, operation, userId, params);
        BIZ_LOGGER.info(message);
    }
    
    /**
     * 接口調用日志(簡潔版)
     */
    public static void apiLog(String apiName, long costTime, Object request, Object response) {
        if (costTime > 3000) {
            // 慢接口使用WARN級別
            log.warn("[API][{}] cost: {}ms, request: {}, response: {}", 
                apiName, costTime, request, response);
        } else {
            log.info("[API][{}] cost: {}ms", apiName, costTime);
        }
    }
    
    /**
     * 方法調用日志(帶耗時)
     */
    public static void methodLog(String methodName, long startTime) {
        long cost = System.currentTimeMillis() - startTime;
        if (cost > 1000) {
            log.warn("[METHOD][{}] cost: {}ms", methodName, cost);
        } else {
            log.debug("[METHOD][{}] cost: {}ms", methodName, cost);
        }
    }
}

5. 敏感信息脫敏工具

package com.example.log.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 日志脫敏工具
 */
@Slf4j
@Component
public class DesensitizationUtil {
    
    @Value("${log.sensitive-fields:}")
    private List<String> sensitiveFields;
    
    private static final Set<String> SENSITIVE_FIELDS = new HashSet<>(Arrays.asList(
        "password", "oldPassword", "newPassword", "idCard", "phone", 
        "bankCard", "token", "secret", "authorization"
    ));
    
    private static final Pattern PHONE_PATTERN = Pattern.compile("(\\d{3})\\d{4}(\\d{4})");
    private static final Pattern ID_CARD_PATTERN = Pattern.compile("(\\d{4})\\d{10}(\\d{4})");
    private static final Pattern BANK_CARD_PATTERN = Pattern.compile("(\\d{4})\\d{10,12}(\\d{4})");
    
    private ObjectMapper objectMapper;
    
    @PostConstruct
    public void init() {
        this.objectMapper = new ObjectMapper();
        this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
        if (sensitiveFields != null) {
            SENSITIVE_FIELDS.addAll(sensitiveFields);
        }
    }
    
    /**
     * 對象脫敏(JSON序列化前處理)
     */
    public String toJsonWithDesensitization(Object obj) {
        try {
            if (obj == null) {
                return "null";
            }
            Object desensitized = desensitize(obj);
            return objectMapper.writeValueAsString(desensitized);
        } catch (JsonProcessingException e) {
            log.error("JSON序列化失敗", e);
            return obj != null ? obj.toString() : "null";
        }
    }
    
    /**
     * 遞歸脫敏
     */
    @SuppressWarnings("unchecked")
    private Object desensitize(Object obj) {
        if (obj == null) {
            return null;
        }
        
        if (obj instanceof Map) {
            Map<String, Object> map = (Map<String, Object>) obj;
            Map<String, Object> result = new HashMap<>();
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                
                if (SENSITIVE_FIELDS.contains(key.toLowerCase())) {
                    result.put(key, "***");
                } else {
                    result.put(key, desensitize(value));
                }
            }
            return result;
        }
        
        if (obj instanceof List) {
            List<Object> list = (List<Object>) obj;
            List<Object> result = new ArrayList<>();
            for (Object item : list) {
                result.add(desensitize(item));
            }
            return result;
        }
        
        // 字符串類型特殊處理
        if (obj instanceof String) {
            String str = (String) obj;
            // 手機號脫敏
            if (str.matches("^1[3-9]\\d{9}$")) {
                return PHONE_PATTERN.matcher(str).replaceAll("$1****$2");
            }
            // 身份證脫敏
            if (str.matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$")) {
                return ID_CARD_PATTERN.matcher(str).replaceAll("$1**********$2");
            }
        }
        
        return obj;
    }
    
    /**
     * 快速脫敏手機號
     */
    public static String maskPhone(String phone) {
        if (phone == null || phone.length() != 11) {
            return phone;
        }
        return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }
    
    /**
     * 快速脫敏身份證
     */
    public static String maskIdCard(String idCard) {
        if (idCard == null || idCard.length() < 18) {
            return idCard;
        }
        return idCard.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1**********$2");
    }
}

6. 全局日志攔截器(AOP實現)

package com.example.log.aspect;

import com.example.log.util.DesensitizationUtil;
import com.example.log.util.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * Controller層日志切面
 */
@Slf4j
@Aspect
@Component
public class ControllerLogAspect {
    
    @Autowired
    private DesensitizationUtil desensitizationUtil;
    
    // 定義切點:所有Controller類下的方法
    @Pointcut("execution(* com.example..controller.*.*(..))")
    public void controllerPointcut() {}
    
    @Around("controllerPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 獲取請求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;
        
        // 獲取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = method.getName();
        
        // 獲取參數(脫敏處理)
        Object[] args = joinPoint.getArgs();
        String params = "";
        if (args != null && args.length > 0) {
            params = Arrays.stream(args)
                .map(arg -> desensitizationUtil.toJsonWithDesensitization(arg))
                .collect(Collectors.joining(", "));
        }
        
        // 請求信息日志
        if (request != null) {
            log.info("【請求開始】{} {} | 參數: {}", 
                request.getMethod(), request.getRequestURI(), params);
        } else {
            log.info("【方法調用】{}.{} 參數: {}", className, methodName, params);
        }
        
        Object result = null;
        try {
            result = joinPoint.proceed();
            long costTime = System.currentTimeMillis() - startTime;
            
            // 響應日志(脫敏處理)
            String responseJson = desensitizationUtil.toJsonWithDesensitization(result);
            log.info("【請求結束】{}.{} 耗時: {}ms | 響應: {}", 
                className, methodName, costTime, responseJson);
            
            // 慢請求告警
            if (costTime > 3000) {
                log.warn("【慢請求】{}.{} 耗時: {}ms", className, methodName, costTime);
            }
            
            return result;
        } catch (Exception e) {
            long costTime = System.currentTimeMillis() - startTime;
            log.error("【請求異常】{}.{} 耗時: {}ms 異常: {}", 
                className, methodName, costTime, e.getMessage(), e);
            throw e;
        }
    }
}

7. MDC鏈路追蹤過濾器

package com.example.log.filter;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;

/**
 * MDC過濾器:實現全鏈路追蹤
 */
@Slf4j
@Component
@Order(1)
public class TraceIdFilter implements Filter {
    
    private static final String TRACE_ID = "traceId";
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String traceId = httpRequest.getHeader("X-Trace-Id");
        
        if (traceId == null || traceId.isEmpty()) {
            traceId = UUID.randomUUID().toString().replace("-", "");
        }
        
        try {
            // 將traceId放入MDC,日志模板中可通過%X{traceId}引用
            MDC.put(TRACE_ID, traceId);
            MDC.put("clientIp", getClientIp(httpRequest));
            
            chain.doFilter(request, response);
        } finally {
            // 清理MDC,避免內存泄漏
            MDC.clear();
        }
    }
    
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty()) {
            ip = request.getRemoteAddr();
        }
        return ip != null ? ip.split(",")[0].trim() : "unknown";
    }
}

8. 業(yè)務中使用示例

package com.example.demo.controller;

import com.example.demo.service.UserService;
import com.example.log.util.LogUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/api/user")
@RequiredArgsConstructor
public class UserController {
    
    private final UserService userService;
    
    @PostMapping("/login")
    public Map<String, Object> login(@RequestBody @Valid LoginRequest request) {
        // 使用Lombok的@Slf4j
        log.info("用戶登錄請求: username={}", request.getUsername());
        
        long startTime = System.currentTimeMillis();
        try {
            UserVO user = userService.login(request);
            
            // 記錄業(yè)務日志
            LogUtil.bizLog("用戶登錄", user.getId(), "login", request.getUsername());
            
            // 記錄方法耗時
            LogUtil.methodLog("login", startTime);
            
            return Map.of("success", true, "data", user);
        } catch (Exception e) {
            log.error("用戶登錄失敗: username={}, error={}", request.getUsername(), e.getMessage(), e);
            throw e;
        }
    }
    
    @PostMapping("/update")
    public Map<String, Object> updateUser(@RequestBody UserUpdateRequest request) {
        // 這里password字段會被自動脫敏
        log.info("更新用戶信息: {}", request);
        
        userService.updateUser(request);
        return Map.of("success", true);
    }
}

// 請求對象示例
@Data
class LoginRequest {
    private String username;
    private String password;  // 會被脫敏
}

@Data
class UserUpdateRequest {
    private String userId;
    private String phone;
    private String idCard;
    private String password;
}

9. 異常統(tǒng)一處理中的日志

package com.example.demo.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(BusinessException.class)
    public Result<?> handleBusinessException(BusinessException e) {
        // 業(yè)務異常:記錄WARN級別即可
        log.warn("業(yè)務異常: code={}, message={}", e.getCode(), e.getMessage());
        return Result.error(e.getCode(), e.getMessage());
    }
    
    @ExceptionHandler(Exception.class)
    public Result<?> handleException(Exception e) {
        // 系統(tǒng)異常:記錄ERROR級別,包含堆棧
        log.error("系統(tǒng)異常", e);
        return Result.error(500, "系統(tǒng)繁忙,請稍后重試");
    }
}

三、總結

最佳實踐總結

原則說明示例
級別正確DEBUG調試、INFO業(yè)務流程、WARN異??苫謴?、ERROR系統(tǒng)錯誤循環(huán)內用DEBUG,關鍵節(jié)點用INFO
參數占位使用{}占位符,避免字符串拼接log.info("user: {}", user)
異常記錄必須傳入異常對象,輸出堆棧log.error("錯誤", e)
異步輸出生產環(huán)境必須配置AsyncAppender使用Disruptor提升性能
鏈路追蹤使用MDC傳遞traceId全鏈路可追蹤
敏感脫敏密碼、手機號等必須脫敏實現自定義脫敏工具
日志開關使用isDebugEnabled()避免無效序列化if(log.isDebugEnabled()){...}
合理采樣高頻日志需采樣1%或千分之一

性能優(yōu)化要點

  1. 異步日志:AsyncAppender + Disruptor,QPS提升5-10倍
  2. 條件日志:使用log.isDebugEnabled()避免參數計算
  3. 合理級別:生產環(huán)境建議INFO,DEBUG僅開發(fā)/測試環(huán)境
  4. 避免打印大對象:大List/大JSON需要截斷或只打印長度

監(jiān)控告警建議

  • ERROR日志數量突增 → 釘釘/企微告警
  • 慢請求日志(>3s) → 性能監(jiān)控
  • 特定業(yè)務日志(登錄失敗頻繁) → 安全告警

日志規(guī)范Checklist

  • 禁止使用System.out.println()
  • 禁止打印密碼、token等敏感信息
  • 日志消息清晰,包含關鍵業(yè)務標識(userId、orderId)
  • 異常日志必須包含堆棧信息
  • 關鍵業(yè)務操作必須有業(yè)務日志
  • 日志文件配置滾動策略和保留時長(建議30天)
  • 生產環(huán)境關閉DEBUG日志

通過以上方案,可以實現生產級的日志系統(tǒng),既保證性能又便于問題排查和監(jiān)控告警。

以上就是SpringBoot中構建生產級日志系統(tǒng)的優(yōu)雅指南的詳細內容,更多關于SpringBoot日志系統(tǒng)的資料請關注腳本之家其它相關文章!

相關文章

  • SpringBoot全局域名替換的實現

    SpringBoot全局域名替換的實現

    本文主要介紹了SpringBoot全局域名替換的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-09-09
  • screw?Maven插件方式運行時在編譯打包時跳過執(zhí)行的問題解決方法

    screw?Maven插件方式運行時在編譯打包時跳過執(zhí)行的問題解決方法

    這篇文章主要介紹了screw?Maven插件方式運行時在編譯打包時跳過執(zhí)行的問題解決方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • Java中將File轉化為MultipartFile的操作

    Java中將File轉化為MultipartFile的操作

    這篇文章主要介紹了Java中將File轉化為MultipartFile的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • mybatis-plus使用xml自定義sql語句方式

    mybatis-plus使用xml自定義sql語句方式

    這篇文章主要介紹了mybatis-plus使用xml自定義sql語句方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java中的可重入鎖ReentrantLock簡析

    Java中的可重入鎖ReentrantLock簡析

    這篇文章主要介紹了Java中的可重入鎖ReentrantLock簡析,可重入是指同一個線程如果首次獲得了這把鎖,那么因為它是這把鎖的擁有者,因此有權利再次獲取這把鎖如果是不可重入鎖,那么第二次獲得鎖時,自己也會被鎖擋住,需要的朋友可以參考下
    2023-12-12
  • spring aop的簡單使用方法詳解

    spring aop的簡單使用方法詳解

    這篇文章主要介紹了spring aop的簡單使用方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • springboot+dubbo實現時間輪算法

    springboot+dubbo實現時間輪算法

    時間輪是一種高效利用線程資源進行批量化調度的算法,本文主要介紹了springboot+dubbo實現時間輪算法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-04-04
  • SpringBoot集成Redis之配置、序列化與持久化方式

    SpringBoot集成Redis之配置、序列化與持久化方式

    本文介紹了Redis的基本概念、常用數據類型及操作、SpringBoot整合Redis的方法、高級特性與安全性、性能優(yōu)化、測試與部署、數據一致性及版本更新等內容,通過本文的學習,讀者可以掌握Redis的使用方法,并在實際項目中發(fā)揮其優(yōu)勢
    2024-11-11
  • Java如何連接數據庫圖文教程

    Java如何連接數據庫圖文教程

    關于java數據庫的文章早已是非常多了,本文是對我個人過往學習java數據庫,理解及應用java數據庫的一個總結,下面這篇文章主要給大家介紹了關于Java如何連接數據庫的相關資料,需要的朋友可以參考下
    2023-04-04
  • js-tab選項卡

    js-tab選項卡

    本文主要介紹了js-tab選項卡的示例代碼。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02

最新評論

乌兰浩特市| 新兴县| 延津县| 浙江省| 扬中市| 滨州市| 荆门市| 汝阳县| 娄底市| 上蔡县| 垣曲县| 金湖县| 铜川市| 武宣县| 青州市| 崇义县| 界首市| 江安县| 鹤山市| 邹城市| 京山县| 平定县| 札达县| 子洲县| 曲靖市| 铜陵市| 永新县| 张家界市| 郑州市| 东港市| 大足县| 宜都市| 汝南县| 保靖县| 邻水| 新兴县| 天峨县| 边坝县| 句容市| 香港| 名山县|