当前位置:   article > 正文

一文弄懂 SpringBoot3 新特性

springboot3

本文参考自:

尚硅谷SpringBoot零基础教程,面试&加薪必会springboot3】 https://www.bilibili.com/video/BV1Es4y1q7Bf/?p=88&share_source=copy_web&vd_source=d45508e20b7e3eae6233a57ab7104d22

1.前置要求

1.环境要求

环境&工具版本(or later)
SpringBoot3.0.5+
IDEA2021.2.1+
Java17+
Maven3.5+
Tomcat10.0+
Servlet5.0+
GraalVM Community22.3+
Native Build Tools0.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.自动配置包位置变化

  1. SpringBoot2.X

    META-INF/spring.factories

    在这里插入图片描述

  2. 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>
  • 1
  • 2
  • 3
  • 4
  • 5

改为

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-3-starter</artifactId>
    <version>1.2.20</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

3.新特性–Problemdetails

SpringBoot3提供的一个新规范,当发生某些异常时,以RFC 7807规范方式返回错误数据

原理

  1. 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();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  2. 处理以下异常。如果系统出现以下异常,会被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
    		})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

效果

spring.mvc.problemdetails.enabled=true
  • 1

开启后 会使用新的MediaType

Content-Type: application/problem+json+ 额外扩展返回
  • 1

并且返回信息也会变化

例:写一个GET接口,用POST访问

在这里插入图片描述

原因:主要是因为该请求异常被 HttpRequestMethodNotSupportedException拦截了

4.新特性–函数式接口

SpringMVC 5.2 以后 允许我们使用函数式的方式,定义Web的请求处理流程

函数式接口

Web请求处理的方式:

  1. @Controller + @RequestMapping耦合式路由业务耦合)
  2. 函数式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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
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();
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

5.支持GraalVM与AOT

  • AOT 提前编译:程序执行前,全部先编译成机器码

  • JIT 即使编译:程序边 编译,边运行

    JITAOT
    优点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应用程序的方式:

    1. 在HotSpot JVM上使用Graal即时(JIT)编译器
    1. 作为预先编译(AOT)的本机可执行文件运行(本地镜像)。

GraalVM的多语言能力使得在单个应用程序中混合多种编程语言成为可能,同时消除了外部语言调用的成本。

具体示例:7、AOT (yuque.com)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/504804
推荐阅读
相关标签
  

闽ICP备14008679号