Springboot2.x升级到3.x的经验分享

升级原因

随着Spring 各种漏洞的更新发布,springboot升级到3.x迫在眉睫。

2.x升级到3.x是一次大的跨越,以下内容是升级时需要注意的一些地方。

JDK的变化

Spring Boot 3.x 需要 Java 17或更高版本,下载地址Java Archive Downloads,根据自己的系统版本选择下载即可。

Oracle JDK版本说明:

JDK8 之前版本,仍然免费。
JDK8 免费版本到 8u202,从 8u211版本开始收费。
JDK9-10,全版本免费。
JDK11,免费版本到 11.0.2,从 11.0.3 版本开始商用收费。
JDK12-16,全版本商用收费。
JDK17-20,全版本(二进制版本)免费。

特别提醒:
JDK17之后的版本可以免费分发和商用,但是仅有3年时间,3年后无法免费商用。
建议使用OpenJDK是一个最常见的选择,因为它完全免费且开源,能够满足大多数开发需求。

OpenJDK下载地址:OpenJDK Downloads

Linux系统同时安装多个版本的JDK,切换方法如下:

# 需要去除已经配置好的jdk环境变量,通常配置在类似以下文件中
/etc/profile.d/jdk.sh
/etc/profile

# 解压安装包到指定目录
tar -xvf openjdk-21_linux-x64_bin.tar.gz -C /usr/local
# 安装Java环境(末尾参数指优先级,数字越大优先级越高)
update-alternatives --install /usr/bin/java java /usr/local/openjdk-8/bin/java 1
update-alternatives --install /usr/bin/java java /usr/local/openjdk-21/bin/java 2
# 配置Java环境
update-alternatives --config java
# 添加执行权限
chmod +x /usr/bin/java
# 查看Java版本
java -version
# 卸载Java环境
update-alternatives --remove java /usr/local/openjdk-8/bin/java

配置变化

Redis配置变化

Redis配置对比2.x版本,在spring下多了一个data层级,如下所示:
image

日志配置变化

日志配置主要是日志的大小和保存历史等配置项和2.x版本不同,3.x版本增加了logback节点,如下所示:
image

代码变化

更新依赖包

<!-- java.version升级为21 -->
<java.version>21</java.version>

<!-- spring-boot版本升级为3.3.5 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>3.3.5</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

<!-- 阿里数据库连接池修改boot-3 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-3-starter</artifactId>
    <version>1.2.21</version>
</dependency>

<!-- mysql的依赖替换成 mysql-connector-j -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.2.0</version>
</dependency>

<!-- SpringBoot3.x使用了Jakarta EE的标准,修改servlet包,原包是javax.servlet -->
<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.0.0/version>
</dependency>
<!-- JAXB来处理XML数据,jaxb在Java 9及更高版本中不再默认包含,需要手动添加相关依赖 -->
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>

替换druid.spring.boot3的包

import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;

javax.servlet包替换为jakarta.servlet

涉及的类包括ServletRequest、HttpServletRequest、ServletResponse、HttpServletResponse等,如下图所示:
image
image

javax.validation包替换为jakarta.validation

涉及的注解包括@Valid、@NotNUll、@NotBlank、@NotEmpty等。

其他javax相关的包替换

javax.persistence.*   -> jakarta.persistence.*
javax.annotation.*    -> jakarta.annotation.*
javax.transaction.*   -> jakarta.transaction.*

支持跨域设置addAllowedOriginPattern

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfig = new CorsConfiguration();
        // 是否允许请求带有验证信息
        corsConfig.setAllowCredentials(true);
        // 设置访问源地址
        //corsConfig.addAllowedOrigin("*");
        corsConfig.addAllowedOriginPattern("*");
        // 设置访问源请求头
        corsConfig.addAllowedHeader("*");
        // 设置访问源请求方法:post,get,put,delete
        corsConfig.addAllowedMethod("*");
        // 对接口配置跨域设置
        source.registerCorsConfiguration("/**", corsConfig);
        return new CorsFilter(source);
    }
}

Spring MVC 和 WebFlux的URL匹配更改

从 Spring Framework 6.0 开始,尾部斜杠匹配配置选项已为 deprecated,其默认值设置为 false。

简单来说,就是比如以前@GetMapping("/list") 这样的控制器,可以通过 /list/list/ 两个路径都能访问到,现在只能通过 /list 访问。

调用python接口的开发者要注意,因为python的开发者习惯在路径最后加个斜杠,java的开发者几乎不会去加,如果调用接口的时候默认都在最后加了斜杠的话,那么springboot升级后,后台将会报请求的资源路径不存在的错误。部署之前需要前端排查一下,要么后端加上包含最后有斜杠的路由,要么前端去掉斜杠后访问接口。

mybatis-plus依赖包替换

如果使用了mybatis-plus的话需要将mybatis-plus-boot-starter依赖包替换成mybatis-plus-spring-boot3-starter,如果用到了代码生成器mybatis-plus-generator的话,还要同时升级代码生成器的依赖包,我这里升级到3.5.9版本,升级后如下:

<!-- mybatis plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.9</version>
</dependency>
<!-- mybatis plus 代码生成器依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.9</version>
</dependency>
<!-- MyBatis-Plus和PageHelper都同时使用到一个jsqlparser的依赖库,然后,PageHelper要求使用的版本与jsqlparser版本有一个对应关系。 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-jsqlparser</artifactId>
    <version>3.5.9</version>
</dependency>
<!-- 升级完MyBatis-Plus之后。PageHelper就不能用了。PageHelper目前也是用的最新的 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>2.1.0</version>
    <exclusions>
       <!-- 由于版本冲突,已单独引用,这里需要排除掉 -->
        <exclusion>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
        </exclusion>
       <!-- 由于mybatis-plus-spring-boot3-starter中包含了以下依赖,且版本不同,这里也需要排除掉 -->
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
        </exclusion>
    </exclusions>
</dependency>

启用 -parameters 编译器标志

使用最新版的 Springboot 3 搭建环境进行开发,调用接口时出现奇怪的错。报错主要信息如下:

Name for argument of type [java.lang.String] not specified, and parameter name information not available via reflection. Ensure that the compiler uses the ‘-parameters’ flag.

新版本调整了参数,而spring会自动帮助设置,导致编译时选项“-参数”被禁用。也就是错误信息中的最后提示:Ensure that the compiler uses the '-parameters' flag.

在spring6中,默认情况下Java编译时,不会保留方法参数的名称,这是为了减小生成的字节码文件的大小;为了可以使用忽略@RequestParam注解的效果,这里需要加上编译选项-parameters

如果不配置,则在使用@PathVariale("id")注解时必须带参数名,get接口定义参数必须使用注解@RequestParam(value = "name", required = false)

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <!-- 注意与本地Maven版本是否兼容,3.12.1->maven3.6.2, 3.13.0->maven3.6.3 -->
            <version>3.12.1</version>
            <configuration>
                <!-- 启用 -parameters 编译器标志 -->
                <parameters>true</parameters>
                <source>21</source>
                <target>21</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

-parameters 是一个编译器参数,它的作用是在编译 Java 源代码时保留方法参数的名称。这对于反射和某些框架(如 Spring)非常有用,它们需要通过参数名称来进行操作。

修改SecurityConfig配置类

点击查看代码
/**
 * spring security配置
 */
@EnableMethodSecurity(securedEnabled = true)
@Configuration
public class SecurityConfig {
    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 认证失败处理类
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;

    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;

    /**
     * 跨域过滤器
     */
    @Autowired
    private CorsFilter corsFilter;

    /**
     * 允许匿名访问的地址
     */
    @Autowired
    private PermitAllUrlProperties permitAllUrl;

    /**
     * @return
     * @throws Exception
     */
    @Bean
    AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        // 身份认证接口
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
        return new ProviderManager(daoAuthenticationProvider);
    }

    /**
     * anyRequest | 匹配所有请求路径
     * access | SpringEl表达式结果为true时可以访问
     * anonymous | 匿名可以访问
     * denyAll | 用户不能访问
     * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
     * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
     * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
     * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
     * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
     * hasRole | 如果有参数,参数表示角色,则其角色可以访问
     * permitAll | 用户可以任意访问
     * rememberMe | 允许通过remember-me登录的用户访问
     * authenticated | 用户登录后可访问
     */
    @Bean
    SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                // CSRF禁用,因为不使用session
                .csrf(AbstractHttpConfigurer::disable)
                // 禁用HTTP响应标头
                .headers(header -> header.cacheControl(HeadersConfigurer.CacheControlConfig::disable).frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
                // 认证失败处理类
                .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
                // 基于token,所以不需要session
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 注解标记允许匿名访问的url
                .authorizeHttpRequests((requests) -> {
                    permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll());
                    // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                    requests.requestMatchers("/login", "/register", "/captchaImage").permitAll()
                            // 静态资源,可匿名访问
                            .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**.html", "/**.css", "/**.js", "/profile/**").permitAll()
                            .requestMatchers("/*/api-docs/**", "/*/doc.html", "/druid/**").permitAll()
                            // 除上面外的所有请求全部需要鉴权认证
                            .anyRequest().authenticated();
                })
                // 添加Logout filter
                .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
                // 添加JWT filter
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 添加CORS filter
                .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
                .addFilterBefore(corsFilter, LogoutFilter.class).build();
    }

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

执行cmd命令报错

在升级JDK21后,程序中有使用到Runtime.getRuntime().exec("cmd"),执行报错:java.io.IOException: Cannot run program "bash": error=0

在启动Java程序时,将以下参数添加到命令行中:
java -Djdk.lang.Process.launchMechanism=vfork app.jar

1.这个配置项是针对Java程序的一个内部属性,用于指定Process类使用的创建子进程的机制。用于创建子进程,它与常用的fork系统调用类似;
2.在一般情况下,你不需要手动设置这个属性,因为Java会根据不同的操作系统自动选择合适的机制。如果你在特定的操作系统和Java版本下遇到与Process相关的问题,并且你确认是由于vfork机制引起的,那么你可以通过在Java启动时添加以下参数来设置这个属性;
3.请注意vfork是一个较老的系统调用,可能在某些操作系统或者Java版本中已经被弃用或不支持。

循环依赖问题

自SpringBoot2.6.0版本开始默认禁止了循环依赖,建议开发者自己写代码的时候去减少不必要的互相依赖。如果程序中出现循环依赖就会报错。

解决方案:

1、开启循环依赖(不推荐)

方式1:在全局配置文件设置允许循环引用存在

spring:
   main:
      allow-circular-references:true #允许循环引用

方式2:在SpringApplicationBuilder 添加设置允许循环引用

public static void main(String[] args) {
  new SpringApplicationBuilder(DemoApplication.class).allowCircularReferences(true).run(args);
}

新项目不推荐此配置,主要针对旧项目升级用此配置处理比较方便快捷。
不推荐原因:
性能开销:Spring 会使用代理对象来解决循环依赖的问题。这种方式会增加额外的性能开销和复杂性‌。
潜在问题:循环依赖可能导致无限递归、死锁等问题,这些问题可能会影响系统的稳定性和性能。
设计缺陷:循环依赖通常是由于设计上的缺陷导致的,我们不应该过度依赖 Spring 而忽视了编码的规范和质量。

2、懒加载

@Lazy:配合使用该注解可以解决循环依赖问题(在需要注入Bean的地方加上该注解)

@Lazy // 使用懒加载
@Autowired
private OneService oneService;

@Lazy 不能解决构造函数循环依赖。
@Lazy 可以推迟 Bean 的加载,但无法解决循环依赖的根本问题。
过度使用@Lazy会隐藏真正的初始化顺序和依赖问题,使得调试变得困难。

3、控制反转

每次使用的时候就去Bean工厂里去获取,这样就不存在循环依赖了

@Service
@RequiredArgsConstructor // 该注解的使用在下面会有介绍和说明
public class OneServiceImpl implements OneService {
    private final ConfigurableListableBeanFactory beanFactory;
    //代替循环依赖
    public TwoService getTwoService(){
        return beanFactory.getBean(TwoService.class);
    }
}

@RequiredArgsConstructor使用说明
@RequiredArgsConstructor:该注解是由Lombok提供,可以解决掉大量重复的@Autowired代码
注意:使用@RequiredArgsConstructor时,需要使用final关键字
写在类上可以代替@Autowired注解,需要注意的是在注入时需要用final定义,或者使用@notnull注解

@RestController
@RequiredArgsConstructor // 代替@Autowired注解
@RequestMapping("/api/v1/one")
public class OneController{
    private final OneService oneService; // 需要final关键字
    private final TwoService twoService; // 需要final关键字
    @GetMapping("{id}")
    public ResultVo<String> getDetails(@PathVariable("id") Long id){
        return ResultVo.ok(oneService.getDetailsById(id));
    }
}

注意点:
1、必须声明的变量为final。
2、根据构造器注入的,相当于容器调用带有一组带有参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。基于构造方法为属性赋值,容器通过调用类的构造方法将其进行依赖注入。
3、当需要注入Bean的时候可以直接在类名称上使用@RequiredArgsConstructor,从而代替了大量的@Autowrited注解。

自动配置包位置变化

  • SpringBoot2.xMETA-INF/spring.factories
    image

  • SpringBoot3.xMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
    image

集成Knife4j-4.5.0

SpringBoot升级至3.x后,Knife4j进行同步升级(Spring Boot 3 只支持OpenAPI3规范),需要把knife4j-spring-boot-starter依赖替换成knife4j-openapi3-jakarta-spring-boot-starter,以下是升级过程与注意事项等。

更新依赖包

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
    <version>4.5.0</version>
</dependency>

YML配置

# springdoc配置
springdoc:
  # get请求多个参数时不需要添加额外的@ParameterObject注解
  default-flat-param-object: true
  api-docs:
    # 线上禁用,配合knife4j.enable=false一起使用才有效果
    enabled: true
# Knife4j配置
knife4j:
  enable: true
  setting:
    language: zh_cn

Knife4jConfig配置类

@Configuration
public class Knife4jConfig
{
    /**
     * 自定义分组
     */
    @Bean
    public GroupedOpenApi api(){
        return GroupedOpenApi.builder()
                .group("api")
                .displayName("业务接口")
                // 指定包分组
//                .packagesToScan("com.cn.web.controller.common", "com.cn.web.controller.editor")
                // 扫描使用@Operation注解的接口
                .addOpenApiMethodFilter(method -> method.isAnnotationPresent(io.swagger.v3.oas.annotations.Operation.class))
                .build();
    }

    /**
     * 创建API
     */
    @Bean
    public OpenAPI customOpenApi()
    {
        return new OpenAPI()
                .components(new Components().addSecuritySchemes(HttpHeaders.AUTHORIZATION, securityScheme()))
                .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION))
                .info(getApiInfo());
    }

    /**
     * 安全模式,这里指定token通过Authorization头请求头传递
     */
    @Bean
    public SecurityScheme securityScheme()
    {
        return new SecurityScheme()
                .type(SecurityScheme.Type.APIKEY)
                .name("Authorization")
                .in(SecurityScheme.In.HEADER)
                .scheme("Bearer");
    }


    /**
     * 添加摘要信息
     */
    private Info getApiInfo()
    {
        return new Info()
            // 设置标题
            .title("XXX服务_接口文档")
            // 描述
            .description("...")
            // 作者信息
            .contact(new Contact().name("hviger"))
            // 版本
            .version("1.0");
    }
}

添加全局请求头

@Component
public class Knife4jOperationCustomizer implements GlobalOperationCustomizer {
    @Override
    public Operation customize(Operation operation, HandlerMethod handlerMethod) {
        List<SecurityRequirement> security = operation.getSecurity();
        if (security == null) {
            security = List.of(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
            operation.setSecurity(security);
        }
        return operation;
    }
}

注解替换

swagger 3 注释的包是io.swagger.v3.oas.annotations

1、原生注解更新

# Controller注解更新
@Api@Tag
@ApiSort@ApiSupport

# 类接口注解更新
@ApiIgnore@Parameter(hidden = true)或@Operation(hidden = true)或@Hidden
@ApiImplicitParam@Parameter
@ApiImplicitParams@Parameters
@ApiOperation(value = "foo", notes = "bar") → @Operation(summary = "foo", description = "bar")
@ApiResponse(code = 404, message = "foo") → @ApiResponse(responseCode = "404", description = "foo")

# 实体类注解更新
@ApiModel@Schema
@ApiModelProperty(hidden = true) → @Schema(accessMode = READ_ONLY)
@ApiModelProperty@Schema
@ApiParam@Parameter

2、全局替换示例

## 全局替换原有注解

@Api(tags
->
@Tag(name

@ApiSort(
->
@ApiSupport(order = 

, dataType = "Integer", dataTypeClass = Integer.class
-> 
, in = ParameterIn.DEFAULT

, dataType = "String", dataTypeClass = String.class
-> 
, in = ParameterIn.DEFAULT

, paramType = "path", in = ParameterIn.DEFAULT
, paramType = "path", dataType = "Integer", dataTypeClass = Integer.class
->
, in = ParameterIn.PATH

, dataType = "Date", dataTypeClass = Date.class
->


@ApiOperation(value
-> 
@Operation(summary

@ApiImplicitParams
-> 
@Parameters

@ApiModel(value | @ApiModelProperty(value
->
@Schema(name | @Schema(description


required = true | required = false (限定为entity或vo等实体类包进行更换)
->
requiredMode = Schema.RequiredMode.REQUIRED
requiredMode = Schema.RequiredMode.NOT_REQUIRED


## javax注解更改(jakarta)

import javax.xxx;
->
import jakarta.xxx;

集成Nacos

更新依赖包

如果你的springboot版本是3.2.x及以上,请添加cloud的包,nacos服务端需要安装最新版本2.4.3

<!--nacos配置中心-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2023.0.1.2</version>
</dependency>

端口授权问题

在Nacos 2.x版本中,默认使用的端口为8848(HTTP管理端口)、9848(客户端gRPC请求服务端端口)和9849(服务端gRPC请求服务端端口)。

客户端在连接时,虽然主要配置的是管理端访问端口8848,但实际上客户端会根据服务端的配置自动计算其他端口进行通信。

Nacos服务端的主端口由server.port指定,gRPC端口为(主端口+1000)。

通过修改Nacos的配置文件application.properties来实现:

server.port=8848
# 配置gRPC端口的偏移量
nacos.server.grpc.port.offset=1

SpringBoot3的新特性

  1. 支持 Java 17
    Spring Boot 3 要求最低 Java 17,这意味着开发者可以利用 Java 17 的新特性,如密封类(Sealed Classes)、模式匹配等。

  2. 支持 Jakarta EE 9
    Spring Boot 3 升级到了 Jakarta EE 9,将 javax.* 命名空间迁移到了 jakarta.*。这一变化影响了与 Jakarta EE 相关的依赖,如 JPA、Servlet 等。

  3. GraalVM 原生镜像支持
    Spring Boot 3 增强了对 GraalVM 原生镜像的支持,使得 Spring 应用可以编译为原生可执行文件,从而显著提升启动速度和减少内存占用。

  4. 改进的 Micrometer 支持
    Micrometer 是 Spring Boot 的指标收集库,Spring Boot 3 进一步增强了与 Micrometer 的集成,提供了更多的开箱即用的指标收集功能。

  5. 新的 AOT(Ahead-of-Time)编译支持
    Spring Boot 3 引入了对 AOT 编译的支持,允许在应用启动前进行部分编译,从而优化启动时间和运行时性能。

  6. 增强的安全特性
    Spring Boot 3 引入了更多的安全特性,包括对 OAuth2 和 OpenID Connect 的改进支持,以及对 Spring Security 6 的全面支持。

  7. 改进的依赖管理
    Spring Boot 3 进一步优化了依赖管理,减少了不必要的依赖冲突,并提供了更清晰的依赖树。

  8. 新的 Starter 和自动配置
    Spring Boot 3 引入了新的 Starter 和自动配置,简化了与第三方库的集成,如 Kafka、Cassandra 等。

  9. 改进的测试支持
    Spring Boot 3 增强了测试支持,提供了更多的测试工具和注解,使得编写和运行测试更加方便。

  10. 更好的可观测性
    Spring Boot 3 提供了更好的可观测性支持,包括对分布式追踪、日志记录和指标收集的改进。

  11. Kotlin 1.7 支持
    Spring Boot 3 支持 Kotlin 1.7,允许开发者使用 Kotlin 的最新特性来编写 Spring 应用。

  12. 改进的错误处理和日志记录
    Spring Boot 3 改进了错误处理和日志记录机制,使得调试和排查问题更加方便。

  13. 新的配置属性
    Spring Boot 3 引入了许多新的配置属性,允许开发者更灵活地配置应用行为。

  14. 弃用和移除的功能
    Spring Boot 3 弃用了一些过时的功能,并移除了一些不再维护的依赖,以保持代码库的简洁和现代性。

  15. 改进的文档和示例
    Spring Boot 3 提供了更详细的文档和示例,帮助开发者更快地上手和掌握新特性。

本文作者:盗梦笔记

本文链接:https://www.cnblogs.com/zhaojinhui/p/18619651

版权声明:本作品采用zhaojh许可协议进行许可。

posted @   盗梦笔记  阅读(1019)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示