https://www.huangdf.xyz/categories/study-notes
南风
南风
发布于 2025-08-06 / 2 阅读
0
0

项目升级jdk(8->21)

项目最终还是升级了jdk,8作为长期免费商用的最后一个版本,商业型公司不换也无伤大雅。但个人开发者能拥抱新技术还是拥抱新技术好些。毕竟一年也就1000来人名币(购买jdk的话)。Java8是2014年发布的,距今已达11年之久,如果个人开发者仍旧停留在8,那是不合适的,受限于技术,8相较于后续版本是有一些局限性的,所以,使用新技术吧。虽然java21是23年发布的,最新的已经到24了,不过升级到了21,再24也就不远了。

1、javax->jakarta

在jdk11这个版本,javax除了包含在jdk包中javax.sql之外的都从javax变成了jakarta。

例如jakarta.servlet、jakarta.annotation、jakarta.validation、jakarta.mail等等,都从javax替换成了jakarta。

2、springboot版本

升级到jdk21之后,springboot的版本也会随之变化。从jdk17开始不支持springboot2,需要升级到3。

spring framework方面

sp3是基于spring framework6这个框架,该框架全面支持Jakarta ee 9,并优化了很多核心功能。相较之下,sp2使用的是spring framework 5。

原生镜像支持方面

sp3引入了对graalvm的支持。graalvm是一个高性能的jvm和多语言运行时能够将java编译成原生可执行文件。

配置文件方面

对于部分配置在3中进行了调整,例如在2中redis的配置是属于spring的下一级, 而到了3中,则是在spring.data下。3对于配置属性进行了更严格的校验和提示。

性能方面

3通过优化核心代码和引入原生镜像支持,优化了启动时间。内存方面3也通过更高效的内存管理和资源分配,减少了应用的内存占用。对于在资源受限的情况下运行的应用比较有帮助。此外还提升了在高并发和高负载的情况下的瓶颈(相较于sp2)。

兼容性和迁移方面

依赖方面

大多数依赖可以通过引入父项目进行管理

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.2.5</version>
</parent>

少部分依赖需要手动调整版本,依赖版本可以通过Maven Repository: Search/Browse/Explore这个网站查询版本,找一个和jdk差不多时间出来的版本,换上看看有没有冲突就行。

api方面

因为依赖升级,导致部分api不可用或是有了更好的替代。需要更新api的逻辑。

以上是一些比较宽泛的修改,接下来是正式遇到的问题。

3、api修改

3.1、security

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

这个依赖的版本随着jdk升级到21,版本从5.x变成了6.x。其中部分api不可用。需要做出调整。

在配置类方面,5.x是通过继承WebSecurityConfigurerAdapter这个类,重写里面的configure方法来实现对配置的修改,而到了6.x,WebSecurityConfigurerAdapter这个类被删除,只能通过bean的方式进行配置修改。

明文不加密

在security5.x版本就已经提示过NoOpPasswordEncoder这个类将过期,建议换一个使用。在6.x中想要实现密码明文不加密的效果只能从写PasswordEncoder,自定义加密规则。下面是5.x和6.x的写法。

加密规则是不加密,匹配规则是equals。简单粗暴。

# 6.x    
@Bean
public PasswordEncoder passwordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                return rawPassword.toString();
            }
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return rawPassword.toString().equals(encodedPassword);
            }
        };
    }
# 5.x
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {  		auth.userDetailsService(userDetailsService).passwordEncoder(NoOpPasswordEncoder.getInstance());
}

访问设置

6.x版本修改了部分api,并且增加了链式表达,并且增加了一些新的api,例如登出成功后的操作,如果登录页面放在静态文件里面,可以设置登出成功就回到登陆页面。此外也有登录失败去往什么页面,会有一个重定向的操作。

6.x

@Bean
protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(AbstractHttpConfigurer::disable)//关闭csrf跨站伪造访问
                .exceptionHandling(new HandleAccessDeniedException())
                .authorizeHttpRequests(auth -> {
                    auth.requestMatchers("/api/user/login", "/api/user/logout").permitAll();//能直接访问
                    auth.anyRequest().authenticated();//需要权限
                }).httpBasic(Customizer.withDefaults())//添加form表单支持,因为配置了url,默认不再支持form表单登录↓
                .formLogin(loginConfigurer -> loginConfigurer.loginPage("/api/user/login").permitAll())
                .logout(logoutConfigurer -> logoutConfigurer.logoutSuccessUrl("/api/user/login").permitAll())
                .addFilterBefore(customerAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

5.x

@Override
protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //设置访问权限,匿名访问
                .antMatchers("/user/login").anonymous()
                .antMatchers("/exam/**").hasRole("admin")
                //其他的都能直接访问
                .anyRequest().permitAll()
                .and()
                //开启异常处理
                .exceptionHandling()
                //设定为自定义的异常处理类.
                .accessDeniedHandler(new HandleAccessDeniedException())
                .and()
                //添加form表单支持,因为配置了url,默认不再支持form表单登录
                .formLogin()
                .and()
                .addFilterBefore(customerAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                //关闭csrf跨站伪造访问
                .csrf().disable();
    }

AuthenticationManager

在5.x版本是通过父类创建对象,到了6.x版本则是通过provider创建对象。

6.x

    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder());
        return new ProviderManager(provider);
    }

5.x

   @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

3.2、MP

如果项目采用的是mybatis-plus,升级到sp3.x之后,需要同步升级mp。

在sp2中mybatisplus依赖名称是:

 		<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.6</version>
        </dependency>

而到了3.x后需要换成

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.10</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-jsqlparser</artifactId>
            <version>3.5.10</version>
        </dependency>

多了个3。另外还需要引入jsqlparser这个依赖,否则拦截器可能不生效。

3.3、swagger

swagger提供了丰富的注解,不管是导出到apifox还是使用原生的swagger文档,都是相当方便的。从sp2到sp3,swagger也需要作出不少修改。

3.3.1、注解

@Api->@Tag(name=")
@ApiModel->@Schema(title="")
@ApiModelProperty->@Parameter(name="")
@ApiOperation->@Operation(summery="")

更多的可以去看看文档,这里只是几个比较常用的注解

3.3.2、依赖

旧版本依赖是这个,而到了sp3中需要改成springdoc的版本。

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
       <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
            <version>2.8.8</version>
        </dependency>

新版本的swagger支持更丰富的注释,同时也更加符合openapi的规范。OpenAPI 3 Library for spring-boot官方文档将就看吧。

3.4、跨域配置

public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedHeaders("*")
                .allowedMethods("*")
                .maxAge(3600)
                .allowCredentials(true);
    }

在这个配置类中,sp2可以通过allowedOrigins("/*")来设置通配,而到了sp3之后,任然使用这个api的话会被警告不允许使用/*,所以要么按照allowedOrigins("string1","string2"...)这个格式,将允许的放进去,要么换成allowedOriginPatterns("/*")。出于安全考虑,确实应该限制跨域访问的源。

4、springframework

不同的依赖中可能都有spf这个包,不同的依赖中版本还可能不一样,所以最好是通过maven的插件,手动排除一些依赖,以免在需要spf6的地方用上了spf5。


评论