SpringBoot 3 新特性

目录

    • [1. GraalVM](#1. GraalVM)
      • [1.1 生成本地可执行应用](#1.1 生成本地可执行应用)
      • [1.2 生成docker镜像](#1.2 生成docker镜像)
    • [2. 支持虚拟线程](#2. 支持虚拟线程)
    • [3. HTTP Interface](#3. HTTP Interface)

1. GraalVM

  • 使用GraalVM将SpringBoot应用程序编译成本地可执行的镜像文件,可以显著提升启动速度、峰值性能以及减少内存应用。
  • 传统的应用都是编译成字节码,然后通过JVM解释并最终编译成机器码来运行,而Spring Native则是通过AOT提前编译为机器码,在运行时直接静态编译成可执行文件,比如windows上的.exe文件,不依赖JVM。GraalVM的即时编译器和AOT编译器可以显著提高应用程序的性能。
  • AOT: Ahead-of-Time Compilation,预编译在Java9中作为实验性功能提出。将Java类编译为本机代码,减少Java应用的启动时间和内存占用。

1.1 生成本地可执行应用

  • maven使用的插件
properties 复制代码
<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
</plugin>
  • 生成本地应用命令
shell 复制代码
mvn -Pnative native:compile
  • gradle需要使用下面的插件
properties 复制代码
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.2'
    id 'io.spring.dependency-management' version '1.1.4'
    id 'org.graalvm.buildtools.native' version '0.9.28'
}
  • 生成本地应用命令
shell 复制代码
gradle nativeCompile
  • 或者在IDEA中点击build下的nativeCompile
  • 最后会在build/native/nativeCompile下生成一个本地可执行文件,可以双击运行
  • 启动速度只有毫秒级

1.2 生成docker镜像

  • maven使用的命令
shell 复制代码
mvn -Pnative spring-boot:build-image
  • gradle使用的命令
shell 复制代码
gradle bootBuildImage
  • 或者在IDEA中点击build下的bootBuildImage
  • 因为这里会通过docker拉取其他的依赖,所以这时候需要启动docker,通过docker客户端会发现多了3个image,后面显示的created时间是错的,不需要在意
shell 复制代码
paketobuildpacks/run-jammy-tiny
paketobuildpacks/builder-jammy-tiny
# tptpbfysrt会每次不一样
pack.local/builder/tptpbfysrt
  • 然后会自动使用pack.local/builder/...启动一个container用来创建镜像,会下载很多东西,如果执行失败,再次点击start运行即可,不会重新下载已经下载过的文件,不要重新执行gradle bootBuildImage命令,不然会全部从头开始执行一遍下载依赖的过程,非常耗费时间。
  • 执行成功后,会在images中出现一个新生成的镜像文件
  • 使用下面命令启动
shell 复制代码
# myproject:0.0.1-SNAPSHOT换成你自己的项目名称和版本
docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT

2. 支持虚拟线程

  • Spring Boot3.2开始虚拟线程,需要使用JDK21,并设置以下属性
properties 复制代码
spring.threads.virtual.enabled=true
  • 启用虚拟线程后,Tomcat 和 Jetty 将使用虚拟线程处理请求。这意味着处理网络请求的应用代码(如Controller中的方法)将在虚拟线程上运行。下面是Tomcat开启虚拟线程的代码,在tomcat-embed-core-10.1.19.jar!\org\apache\tomcat\util\net\AbstractEndpoint.class中
java 复制代码
    public void createExecutor() {
        internalExecutor = true;
        if (getUseVirtualThreads()) {
            executor = new VirtualThreadExecutor(getName() + "-virt-");
        } else {
            TaskQueue taskqueue = new TaskQueue();
            TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
            executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
            taskqueue.setParent( (ThreadPoolExecutor) executor);
        }
    }
  • 创建一个controller
  • 启动程序,调用hello接口,查看日志打印
shell 复制代码
2024-02-24T16:41:15.778+08:00  INFO 14252 --- [omcat-handler-0] com.example.demo.Controller : [Controller][hello] VirtualThread[#46,tomcat-handler-0]/runnable@ForkJoinPool-1-worker-1
  • 通过VirtualThread[#46,tomcat-handler-0]可以看出使用的是虚拟线程
  • 关闭虚拟线程,再次调用接口,查看日志打印
shell 复制代码
2024-02-24T16:43:14.715+08:00  INFO 15844 --- [nio-8080-exec-1] com.example.demo.Controller : [Controller][hello] Thread[#39,http-nio-8080-exec-1,5,main]
  • 通过Thread[#39,http-nio-8080-exec-1,5,main]可以看出使用的是平台线程

3. HTTP Interface

java 复制代码
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.HttpExchange;

@HttpExchange("/api")
public interface HelloClient {

    @GetExchange("/hello")
    String hello(@RequestParam String msg);

}
  • 注入声明式客户端,通过给HttpServiceProxyFactory注入带目标接口baseUrl的client,可以RestClient、WebClient、RestTemplate,这里使用RestClient
java 复制代码
import com.example.springboot3.client.HelloClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.support.RestClientAdapter;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;

@Configuration
public class AppConfig {

    @Bean
    public HelloClient toClient() {
        RestClient restClient = RestClient.builder().baseUrl("http://localhost:80/").build();
        HttpServiceProxyFactory httpServiceProxyFactory = HttpServiceProxyFactory.builderFor(RestClientAdapter.create(restClient)).build();
        return httpServiceProxyFactory.createClient(HelloClient.class);
    }

}
  • Controller
java 复制代码
import com.example.springboot3.client.HelloClient;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @Resource
    private HelloClient client;

    @GetMapping("hello")
    public String hello(@RequestParam String msg) {
        return client.hello(msg);
    }

}
相关推荐
RuoyiOffice4 小时前
SpringBoot+Vue3+Onlyoffice 企业文件生命周期:上传、业务关联、权限、版本与安全清理
spring boot·vue3·文件管理·对象存储·权限控制·ruoyi office·附件管理
我是人✓4 小时前
Spring IOC注解全解析和Spring整合测试单元
java·后端·spring
智购科技无人售货机工厂店4 小时前
玻璃瓶饮料破损率突然上升,排查发现是取货口缓冲垫老化了~YH
java·开发语言·人工智能·python·eclipse
镜象科技4 小时前
中小学AI心理健康解决方案服务商怎么选?2026年选型参考
android·java·人工智能
阿狗童鞋4 小时前
高并发系统设计实战指南
java·spring boot·spring cloud
Sam_Deep_Thinking4 小时前
CountDownLatch实现原理
java·后端·面试·程序员
小狼Solar4 小时前
SAP MDG 功能范围说明(基于S/4HANA 2025)
java·开发语言
范中勤4 小时前
Python 与 Java:模块、包、对象、反射核心差异总结
java·python·面试·反射·元类
ab1237685 小时前
Spring Integration 完整笔记 + 和 spring-integration-mqtt、Paho、EMQX 的关系
java·笔记·spring
小蜗牛狂飙记5 小时前
java环境一键配置和切换的ui工具
java