开启成长之旅!这是我参加「日新方案 12 月更文应战」的第1天,点击检查活动详情

本文根据 newbeemall 项目晋级Spring Boot3.0踩坑总结而来,附带更新阐明:

Spring-Boot-3.0-发布阐明

Spring-Boot-3.0.0-M5-发布阐明

一. 编译报错,import javax.servlet.*; 不存在

这个报错主要是Spring Boot3.0现已为所有依靠项从 Java EE 迁移到 Jakarta EE API,导致 servlet 包名的修正,Spring团队这样做的原因,主要是避免 Oracle 的版权问题,处理办法很简单,两步走:

1 添加 jakarta.servlet 依靠

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
</dependency>
  1. 修正项目内所有代码的导入依靠
修正前:
import javax.servlet.*
修正后:
import jakarta.servlet.*

二. 附带的很多依靠包晋级,导致的部分代码写法过期报警

2.1 Thymeleaf晋级到3.1.0.M2,日志打印的报警

14:40:39.936 [http-nio-84-exec-15] WARN  o.t.s.p.StandardIncludeTagProcessor - [doProcess,67] - [THYMELEAF][http-nio-84-exec-15][admin/goods/goods] Deprecated attribute {th:include,data-th-include} found in template admin/goods/goods, line 4, col 15. Please use {th:insert,data-th-insert} instead, this deprecated attribute will be removed in future versions of Thymeleaf.
14:40:39.936 [http-nio-84-exec-15] WARN  o.t.s.p.AbstractStandardFragmentInsertionTagProcessor - [computeFragment,385] - [THYMELEAF][http-nio-84-exec-15][admin/goods/goods] Deprecated unwrapped fragment expression "admin/header :: header-fragment" found in template admin/goods/goods, line 4, col 15. Please use the complete syntax of fragment expressions instead ("~{admin/header :: header-fragment}"). The old, unwrapped syntax for fragment expressions will be removed in future versions of Thymeleaf.

能够看出作者很交心,日志里现已给出了晋级后的写法,修正如下:

修正前:
<th:block th:include="admin/header :: header-fragment"/>
修正后:
<th:block th:insert="~{admin/header :: header-fragment}"/>

2.2 Thymeleaf晋级到3.1.0.M2,后端运用 thymeleafViewResolver 手动烘托网页代码报错

// 修正前 Spring Boot2.7:
WebContext ctx = new (request, response,
        request.getServletContext(), request.getLocale(), model.asMap());
html = thymeleafViewResolver.getTemplateEngine().process("mall/seckill-list", ctx);

上述代码中针对 WebContext 对象的创立报错,这儿直接给出新版写法

// 修正后 Spring Boot3.0:
JakartaServletWebApplication jakartaServletWebApplication = JakartaServletWebApplication.buildApplication(request.getServletContext());
WebContext ctx = new WebContext(jakartaServletWebApplication.buildExchange(request, response), request.getLocale(), model.asMap());
html = thymeleafViewResolver.getTemplateEngine().process("mall/seckill-list", ctx);

三. 很多第三方库关于 Spring Bootstarter 依靠失效,导致项目发动报错

博主晋级到3.0后,发现发动时,Druid 数据源开始报错,找不到数据源装备,便怀疑跟 Spring boot 3.0 更新有关

这儿直接给出原因:Spring Boot 3.0 中主动装备注册的 spring.factories 写法已抛弃,改为了 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 写法,导致很多第三方 starter 依靠失效

在吐槽一下,这么重要的更改在Spring官方的 Spring-Boot-3.0-发布阐明 中竟然没有,被放在了 Spring-Boot-3.0.0-M5-发布阐明 中

这儿给出两个处理方案:

  1. 等候第三方库适配 Spring Boot 3.0
  2. 按照 Spring Boot 3.0要求,在项目resources 下新建 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,手动将第三方库的 spring.factories 加到 imports 中,这样能够手动修正第三方库 spring boot starter 依靠失效问题

四. Mybatis Plus 依靠问题

Mybatis plus 最新版别仍是3.5.2,其依靠的 mybatis-spring 版别是2.2.2(mybatis-spring 现已发布了3.0.0版别适配 Spring Boot 3.0),这会导致项目中的sql查询直接报错,这儿主要是因 Spring Boot 3.0中删去 NestedIOException 这个类,在 Spring boot 2.7中这个类还存在,给出类阐明截图

Spring Boot3.0升级,踩坑之旅,附解决方案
这个类在2.7中现已被标记为抛弃,主张替换为 IOException, 而 Mybatis plus 3.5.2中还在运用。这儿给出问题截图 MybatisSqlSessionFactoryBean 这个类还在运用 NestedIOException

Spring Boot3.0升级,踩坑之旅,附解决方案

检查 Mybatis plus 官方issue也现已有人提到了这个问题,官方的说法是 mybatis-plus-spring-boot-starter 还在验证没有推送maven官方库房,这儿我就不得不动用我的小聪明,给出处理方案:

  1. 手动将原有的 MybatisSqlSessionFactoryBean 类代码复制到一个咱们自己代码目录下新建的 MybatisSqlSessionFactoryBean 类,去掉 NestedIOException 依靠
  2. 数据源主动装备代码修正
@Slf4j
@EnableConfigurationProperties(MybatisPlusProperties.class)
@EnableTransactionManagement
@EnableAspectJAutoProxy
@Configuration
@MapperScan(basePackages = "ltd.newbee.mall.core.dao", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class HikariCpConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return new HikariDataSource();
    }
    /**
     * @param datasource 数据源
     * @return SqlSessionFactory
     * @Primary 默许SqlSessionFactory
     */
    @Bean(name = "masterSqlSessionFactory")
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource datasource,
                                                     Interceptor interceptor,
                                                     MybatisPlusProperties properties) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(datasource);
        // 兼容mybatis plus的主动装备写法
        bean.setMapperLocations(properties.resolveMapperLocations());
        if (properties.getConfigurationProperties() != null) {
            bean.setConfigurationProperties(properties.getConfigurationProperties());
        }
        if (StringUtils.hasLength(properties.getTypeAliasesPackage())) {
            bean.setTypeAliasesPackage(properties.getTypeAliasesPackage());
        }
        bean.setPlugins(interceptor);
        GlobalConfig globalConfig = properties.getGlobalConfig();
        bean.setGlobalConfig(globalConfig);
        log.info("------------------------------------------masterDataSource 装备成功");
        return bean.getObject();
    }
    @Bean("masterSessionTemplate")
    public SqlSessionTemplate masterSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

到这儿,项目就能够正常跑起来了

总结

Spring Boot 3.0 晋级带来了很多破坏性更改,把很多依靠晋级到了最新,算是处理了一部分历史问题,也为了云原型需求,逐步适配 graalvm ,不论怎么样作为技术开发者,期望有更多的开发者来测验 Spring Boot 3.0 带来的新变化。