一文弄懂 SpringBoot3 新特性
一文弄懂 SpringBoot3 的改动和新特性
本文参考自:
【尚硅谷SpringBoot零基础教程,面试&加薪必会springboot3】 https://www.bilibili.com/video/BV1Es4y1q7Bf/?p=88&share_source=copy_web&vd_source=d45508e20b7e3eae6233a57ab7104d22
1.前置要求
1.环境要求
环境&工具 | 版本(or later) |
---|---|
SpringBoot | 3.0.5+ |
IDEA | 2021.2.1+ |
Java | 17+ |
Maven | 3.5+ |
Tomcat | 10.0+ |
Servlet | 5.0+ |
GraalVM Community | 22.3+ |
Native Build Tools | 0.9.19+ |
2.SpringBoot是什么
SpringBoot 帮我们简单、快速地创建一个独立的、生产级别的 Spring 应用(说明:SpringBoot底层是Spring)
大多数 SpringBoot 应用只需要编写少量配置即可快速整合 Spring 平台以及第三方技术
特性
- 快速创建独立Spring应用,无需像SSM一样,导一堆的包,写一堆配置
- 直接嵌入Servlet容器,如Tomcat、Jetty等,无需部署 war 包,直接打包成jar包,java -jar执行
- 重点: 提供了可选的场景启动器starter,简化应用整合,Spring Boot会自动管理这些依赖项的版本,确保它们之间的兼容性。
- 重点: 按需自动配置Spring以及第三方库,约定大于配置,每个场景都有默认配置,需要自定义只需要在配置文件修改即可。
- 提供生产级特性,如监控指标、健康检查、外部化配置等
总结:简化开发,简化配置,简化整合,简化部署,简化监控,简化运维。
2.改变&新特性
1.自动配置包位置变化
-
SpringBoot2.X
META-INF/spring.factories
-
SpringBoot3.X
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
2.jakata api迁移
1.SpringBoot2.X
2.SpringBoot3.X
3.SpringBoot3使用druid有问题,因为它引用的是旧的包
该问题已经得到官方解决:
解决SpringBoot3整合Druid的兼容性问题_druid-spring-boot-3-starter-CSDN博客
方法:将依赖有原先的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.18</version>
</dependency>
改为
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.20</version>
</dependency>
3.新特性–Problemdetails
SpringBoot3提供的一个新规范,当发生某些异常时,以RFC 7807
规范方式返回错误数据
原理
-
ProblemDetailsErrorHandlingConfiguration
是一个@ControllerAdvice
集中处理系统异常@Configuration(proxyBeanMethods = false) //配置过一个属性 spring.mvc.problemdetails.enabled=true @ConditionalOnProperty(prefix = "spring.mvc.problemdetails", name = "enabled", havingValue = "true") static class ProblemDetailsErrorHandlingConfiguration { @Bean @ConditionalOnMissingBean(ResponseEntityExceptionHandler.class) ProblemDetailsExceptionHandler problemDetailsExceptionHandler() { return new ProblemDetailsExceptionHandler(); } }
-
处理以下异常。如果系统出现以下异常,会被SpringBoot支持以
RFC 7807
规范方式返回错误数据@ExceptionHandler({ HttpRequestMethodNotSupportedException.class, //请求方式不支持 HttpMediaTypeNotSupportedException.class, HttpMediaTypeNotAcceptableException.class, MissingPathVariableException.class, MissingServletRequestParameterException.class, MissingServletRequestPartException.class, ServletRequestBindingException.class, MethodArgumentNotValidException.class, NoHandlerFoundException.class, AsyncRequestTimeoutException.class, ErrorResponseException.class, ConversionNotSupportedException.class, TypeMismatchException.class, HttpMessageNotReadableException.class, HttpMessageNotWritableException.class, BindException.class })
效果
spring.mvc.problemdetails.enabled=true
开启后 会使用新的MediaType
Content-Type: application/problem+json+ 额外扩展返回
并且返回信息也会变化
例:写一个GET接口,用POST访问
原因:主要是因为该请求异常被 HttpRequestMethodNotSupportedException
拦截了
4.新特性–函数式接口
SpringMVC 5.2
以后 允许我们使用函数式的方式,定义Web的请求处理流程。函数式接口
Web请求处理的方式:
@Controller + @RequestMapping
:耦合式 (路由、业务耦合)- 函数式Web:分离式(路由、业务分离)
核心类
- RouterFunction - 定义路由信息。发什么请求,谁来处理
- RequestPredicate - 定义请求规则:请求谓语。请求方式(GET、POST)、请求参数
- ServerRequest - 封装请求完整数据
- ServerResponse - 封装响应完整数据
示例
package com.atguigu.web.config;
import com.atguigu.web.bean.Person;
import com.atguigu.web.biz.UserBizHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.function.RequestPredicates;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerResponse;
/**
* @author lfy
* @Description
* @create 2023-04-18 21:46
*/
/**
* 场景:User RESTful - CRUD
* ● GET /user/1 获取1号用户
* ● GET /users 获取所有用户
* ● POST /user 请求体携带JSON,新增一个用户
* ● PUT /user/1 请求体携带JSON,修改1号用户
* ● DELETE /user/1 删除1号用户
*/
@Configuration
public class WebFunctionConfig {
/**
* 函数式Web:
* 1、给容器中放一个Bean:类型是 RouterFunction<ServerResponse>,集中所有路由信息
* 2、每个业务准备一个自己的Handler
*
*
* 核心四大对象
* 1、RouterFunction: 定义路由信息。发什么请求,谁来处理
* 2、RequestPredicate:定义请求规则:请求谓语。请求方式(GET、POST)、请求参数
* 3、ServerRequest: 封装请求完整数据
* 4、ServerResponse: 封装响应完整数据
*/
@Bean
public RouterFunction<ServerResponse> userRoute(UserBizHandler userBizHandler/*这个会被自动注入进来*/){
return RouterFunctions.route() //开始定义路由信息
.GET("/user/{id}", RequestPredicates.accept(MediaType.ALL), userBizHandler::getUser)
.GET("/users", userBizHandler::getUsers)
.POST("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userBizHandler::saveUser)
.PUT("/user/{id}", RequestPredicates.accept(MediaType.APPLICATION_JSON), userBizHandler::updateUser)
.DELETE("/user/{id}", userBizHandler::deleteUser)
.build();
}
}
package com.atguigu.web.biz;
import com.atguigu.web.bean.Person;
import jakarta.servlet.ServletException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* @author lfy
* @Description 专门处理User有关的业务
* @create 2023-04-18 21:55
*/
@Slf4j
@Service
public class UserBizHandler {
/**
* 查询指定id的用户
* @param request
* @return
*/
public ServerResponse getUser(ServerRequest request) throws Exception{
String id = request.pathVariable("id");
log.info("查询 【{}】 用户信息,数据库正在检索",id);
//业务处理
Person person = new Person(1L,"哈哈","aa@qq.com",18,"admin");
//构造响应
return ServerResponse
.ok()
.body(person);
}
/**
* 获取所有用户
* @param request
* @return
* @throws Exception
*/
public ServerResponse getUsers(ServerRequest request) throws Exception{
log.info("查询所有用户信息完成");
//业务处理
List<Person> list = Arrays.asList(new Person(1L, "哈哈", "aa@qq.com", 18, "admin"),
new Person(2L, "哈哈2", "aa2@qq.com", 12, "admin2"));
//构造响应
return ServerResponse
.ok()
.body(list); //凡是body中的对象,就是以前@ResponseBody原理。利用HttpMessageConverter 写出为json
}
/**
* 保存用户
* @param request
* @return
*/
public ServerResponse saveUser(ServerRequest request) throws ServletException, IOException {
//提取请求体
Person body = request.body(Person.class);
log.info("保存用户信息:{}",body);
return ServerResponse.ok().build();
}
/**
* 更新用户
* @param request
* @return
*/
public ServerResponse updateUser(ServerRequest request) throws ServletException, IOException {
Person body = request.body(Person.class);
log.info("保存用户信息更新: {}",body);
return ServerResponse.ok().build();
}
/**
* 删除用户
* @param request
* @return
*/
public ServerResponse deleteUser(ServerRequest request) {
String id = request.pathVariable("id");
log.info("删除【{}】用户信息",id);
return ServerResponse.ok().build();
}
}
5.支持GraalVM与AOT
-
AOT 提前编译:程序执行前,全部先编译成机器码
-
JIT 即使编译:程序边 编译,边运行
JIT AOT 优点 1.具备实时调整能力
2.生成最优机器指令
3.根据代码运行情况优化内存占用1.速度快,优化了运行时编译时间和内存消耗
2.程序初期就能达最高性能
3.加快程序启动速度缺点 1.运行期边编译速度慢
2.初始编译不能达到最高性能1.运行期边编译速度慢
2.初始编译不能达到最高性能
语言
-
编译型语言:需要编译器 C C++
-
解释型语言:需要解释器 Python、js、PHP
-
半编译半解释型语言:既有编译器有有解释器 JAVA
GraalVM
GraalVM是一个高性能的JDK,旨在加速用Java和其他JVM语言编写的应用程序的执行,同时还提供JavaScript、Python和许多其他流行语言的运行时。
GraalVM提供了两种运行Java应用程序的方式:
- 在HotSpot JVM上使用Graal即时(JIT)编译器
- 作为预先编译(AOT)的本机可执行文件运行(本地镜像)。
GraalVM的多语言能力使得在单个应用程序中混合多种编程语言成为可能,同时消除了外部语言调用的成本。
具体示例:7、AOT (yuque.com)
更多推荐
所有评论(0)