Spring Boot 3.3.4 升级导致 Logback 之前回滚策略配置不兼容问题解决

前言

在将 Spring Boot 项目升级至 3.3.4 版本后,遇到 Logback 配置的兼容性问题。本文将详细描述该问题的错误信息、原因分析,并提供调整日志回滚策略的解决方案。

错误描述

这是SpringBoot 3.3.3版本之前的回滚策略的配置

    <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>10MB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
        <!--日志文档保留天数-->
        <maxHistory>30</maxHistory>
    </rollingPolicy>

当 升级至 Spring Boot 3.3.4 版本后,启动时出现以下报错:

Exception in thread "main" java.lang.IllegalStateException: java.lang.IllegalStateException: Logback configuration error detected: 
ERROR in ch.qos.logback.core.model.processor.ImplicitModelHandler - Could not create component [timeBasedFileNamingAndTriggeringPolicy] of type [ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP] java.lang.ClassNotFoundException: ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP
ERROR in c.q.l.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy - Filename pattern [/logs/app/%d{yyyy-MM-dd}.%i.log] contains an integer token converter, i.e. %i, INCOMPATIBLE with this configuration. Remove it.

主要问题出现在 logback 日志配置的 SizeAndTimeBasedFNATP 类以及日志文件命名中的 %i 令牌使用上。

关键错误信息:
  1. java.lang.ClassNotFoundException: ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP
  2. Filename pattern contains an integer token converter, i.e. %i, INCOMPATIBLE with this configuration

原因分析

在升级 Spring Boot 版本至 3.3.4 后,底层的 Logback 版本也随之更新。在较新的 Logback 版本中,以下变化引发了兼容性问题:

  1. SizeAndTimeBasedFNATP 类弃用

    • 在新的 Logback 版本中,SizeAndTimeBasedFNATP 类已经被移除或不再使用。之前用来支持基于大小和时间的日志滚动的策略必须替换为新的策略类。
    • 此类需要被 SizeAndTimeBasedRollingPolicy 替代,它能够同时支持按文件大小和时间进行日志滚动。
  2. 日志文件命名中的 %i 令牌不兼容

    • 日志文件命名模式中使用的 %i 令牌,用于在日志滚动时生成多个文件(如 log.1, log.2 等),但这与 TimeBasedRollingPolicy 不兼容。TimeBasedRollingPolicy 仅基于时间滚动日志,不支持 %i 分片。

解决方案

调整日志回滚策略

为了解决以上问题,我们需要将原有的 TimeBasedRollingPolicy 替换为新的 SizeAndTimeBasedRollingPolicy,并调整日志文件的命名模式以去除不兼容的 %i 令牌。

配置修改

以下是修改后的 logback-spring.xml 配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- SpringBoot默认logback的配置 -->
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>

    <springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
    <property name="LOG_HOME" value="/logs/${APP_NAME}"/>

    <!-- 1. 输出到控制台 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>DEBUG</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 2. 输出到文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/log.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} -%5level ---[%15.15thread] %-40.40logger{39} : %msg%n%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 使用SizeAndTimeBasedRollingPolicy替代旧的策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 滚动后的日志文件命名模式 -->
            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!-- 日志文件的最大大小 -->
            <maxFileSize>10MB</maxFileSize>
            <!-- 最大保留30天的日志 -->
            <maxHistory>30</maxHistory>
            <!-- 总日志文件大小不超过3GB -->
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

    <!-- 开发环境输出至控制台 -->
    <springProfile name="dev">
        <root level="INFO">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>

    <!-- 生产环境输出至文件 -->
    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="FILE"/>
        </root>
    </springProfile>

</configuration>
修改内容说明:
  1. 使用 SizeAndTimeBasedRollingPolicy

    • 该策略同时支持按时间和文件大小滚动日志。与旧的 TimeBasedRollingPolicy 类相比,它是更推荐的滚动策略。
  2. 文件命名模式调整

    • fileNamePattern 中,使用 %d{yyyy-MM-dd}-%i.log 作为文件名格式,这允许日志按照日期命名,并在同一天滚动日志时通过 %i 生成分片文件(如 2024-10-01-1.log, 2024-10-01-2.log 等)。
  3. 限制日志大小和保留时间

    • maxFileSize 设置为 10MB,表示单个日志文件的最大大小。
    • maxHistory 设置为 30,表示最多保留30天的日志文件。
    • totalSizeCap 设置为 3GB,表示日志总大小不能超过 3GB。达到该限制时,将删除最早的日志文件。

总结

在 Spring Boot 升级至 3.3.4 后,由于底层 Logback 版本的更新,原先使用的 TimeBasedRollingPolicy 类和日志文件名中的 %i 令牌会引发兼容性问题。通过调整日志回滚策略,使用新的 SizeAndTimeBasedRollingPolicy 并去除不兼容的文件命名模式,可以顺利解决这些问题,使日志系统恢复正常运行。

<think>我们正在解决Spring Boot 3.3.4项目中的编译错误:"无法访问javax.servlet.Filter,找不到javax.servlet.Filter的类文件" 根据错误信息,问题在于缺少javax.servlet.Filter类。在Spring Boot 3.x版本中,一个重要变化是从javax迁移到了jakarta命名空间。 因此,我们需要将javax.servlet替换为jakarta.servlet。 具体步骤: 1. 修改代码中的包导入:将`import javax.servlet.*;`改为`import jakarta.servlet.*;`。 2. 更新依赖:确保依赖的库(如renren-fast)也支持jakarta,或者使用适配器(如果有必要)。 3. 如果项目中有直接依赖javax.servlet-api,需要移除,并替换为jakarta.servlet-api(但Spring Boot 3.x已自动管理此依赖)。 由于错误出现在文件:D:\IdeaProjects\transmall\renren-fast\src\main\java\io\renren\modules\sys\jwt\JWTFilter.java 我们应检查该文件中的import语句。 示例修改: 原代码可能为: import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; // ... 其他javax.servlet的导入 修改后: import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; // ... 其他相应的jakarta.servlet的导入 同时,由于Spring Boot 3.x使用Jakarta EE 9+,因此需要确保所有相关的依赖都升级到支持Jakarta EE 9+的版本。 如果renren-fast模块中的其他类也使用了javax.servlet,同样需要修改。 另外,检查pom.xml中是否引入了正确的Spring Boot starter版本(3.3.4),并且没有引入旧的javax.servlet依赖。 如果项目中有其他依赖(如renren-generator)还在使用javax.servlet,需要升级这些依赖的版本或修改其源码。 由于这是一个较大的变化,建议检查整个项目中所有使用javax.servlet的地方,并替换为jakarta.servlet。 补充:Spring Boot 3.x迁移指南[^1]中提到,从Spring Boot 3.0开始,Servlet API的包名已经改为jakarta.servlet。 因此,解决方案总结: 1. 修改源代码中的import语句,将`javax.servlet`替换为`jakarta.servlet`。 2. 确保Maven依赖中不再包含javax.servlet-api,而是使用Spring Boot自带的jakarta.servlet-api(无需显式添加,因为spring-boot-starter-web已经包含)。 验证步骤: 1. 修改JWTFilter.java文件中的import语句。 2. 重新编译项目。 如果还有其他类似的编译错误,同样按照此方法处理。 注意:如果项目中使用了第三方库,而这些库还没有迁移到jakarta,那么可能需要寻找这些库的Jakarta EE 9+兼容版本,或者使用适配层(例如:org.apache.tomcat:tomcat-jakartaee)进行转换。但在Spring Boot 3.x中,推荐直接使用支持Jakarta EE 9+的库。 根据引用[3],我们知道spring-boot-starter-web已经包含了所需的依赖,所以只要修改导入即可。 因此,针对用户的问题,核心解决步骤就是修改代码中的包导入。 相关问题: 1. Spring Boot 3.x中如何从javax迁移到jakarta? 2. 如何升级Spring Boot 2.x项目到3.x版本? 3.Spring Boot 3.x中使用旧的javax.servlet库会导致什么问题? 我们将按照上述步骤编写答案。 </think>### 解决 Spring Boot 3.3.4 编译错误 "无法访问 javax.servlet.Filter" 的完整方案 #### 问题原因分析 Spring Boot 3.0+ 已完成 Jakarta EE 迁移,不再支持 `javax.servlet` 包。错误本质是: $$ \text{javax.servlet} \xrightarrow{\text{Spring Boot 3.x}} \text{jakarta.servlet} $$ 您的项目依赖仍指向旧的 javax 命名空间[^1],而 Spring Boot 3.3.4 仅支持 Jakarta EE 9+ 规范[^3]。 #### 解决步骤 1. **修改代码中的包导入** 在 `JWTFilter.java` 文件中替换所有 javax 导入: ```diff // 修改前 - import javax.servlet.*; + import jakarta.servlet.*; // 示例:第33行附近修改 public class JWTFilter extends BasicHttpAuthenticationFilter { @Override - protected boolean isAccessAllowed(ServletRequest request, ...) + protected boolean isAccessAllowed(jakarta.servlet.ServletRequest request, ...) } ``` 2. **更新 Maven 依赖配置** 在 `pom.xml` 中移除 javax 声明,添加 Jakarta EE 依赖: ```xml <!-- 移除旧依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- 添加新依赖 --> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <!-- 匹配 Spring Boot 3.3.4 --> <scope>provided</scope> </dependency> ``` 3. **检查父子 POM 兼容性** 确保父 POM 声明了 Spring Boot 3.3.4: ```xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.4</version> </parent> ``` 4. **第三方依赖迁移(关键步骤)** 通过 `mvn dependency:tree` 检查依赖树: ```bash # 检测 javax.servlet 残留 mvn dependency:tree -Dincludes=*:javax.servlet* ``` 若存在第三方库(如 renren-fast)仍依赖 javax: ```xml <dependency> <groupId>com.example</groupId> <artifactId>legacy-lib</artifactId> <exclusions> <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion> </exclusions> </dependency> ``` #### 验证流程 1. **编译验证** ```bash mvn clean compile -DskipTests # 确认无 "javax.servlet" 相关错误 ``` 2. **运行时检查** 启动应用后验证日志: ```log o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) ``` 3. **API 兼容性测试** 在 Controller 中添加测试端点: ```java @GetMapping("/test") public String testServlet(jakarta.servlet.http.HttpServletRequest request) { return "Jakarta EE 9+ works!"; } ``` #### 兼容性处理技巧 1. **临时过渡方案** 若无法立即修改所有代码: ```java import jakarta.servlet.*; import javax.servlet.*; // 不推荐!仅限临时过渡 ``` 2. **组件扫描兼容** Spring Boot 3 需要显式扫描 Jakarta 组件[^1]: ```java @SpringBootApplication(scanBasePackages = "your.package") ``` #### 版本匹配参考 | Spring Boot | Jakarta API | Tomcat | |------------|-------------|--------| | 3.3.x | 6.0.x | 10.1.x | | 3.2.x | 5.0.x | 10.0.x | > **重要提醒**:Spring Boot 3 已彻底放弃 javax 支持,Jakarta EE 迁移是不可逆的[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值