SpringBoot3新特性

news2024/11/29 10:54:55

本篇文章参考尚硅谷springboot3课程: https://www.bilibili.com/video/BV1Es4y1q7Bf?p=94&vd_source=d6deb2b69988de2ae72087817e5143d7
原版笔记:
https://www.yuque.com/leifengyang/springboot3/xy9gqc2ezocvz4wn

1.自动配置包位置变化

现在指定自动配置类放在了下面这个AutoConfiguration.imports文件里面:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
springboot2是放在:
META-INF/spring.factories

2.Java EE API 迁移到 Jakarta EE变体

Spring Boot 3已经将所有Java EE API迁移到其等效的Jakarta EE变体,对于大多数用户来说,这意味着需要将任何javax导入替换为jakarta。例如:javax.servlet.Filter 将被替换为 jakarta.servlet.Filter.

3.新特性 - ProblemDetails、 函数式Web

ProblemDetails: 定义新的错误信息返回格式
遵循RFC 7807: https://www.rfc-editor.org/rfc/rfc7807

problemdetails默认是关闭的,可以在application.properties里面打开:
spring.mvc.problemdetails.enabled=true

原理:
WebMvcAutoConfiguration 里面定义了–> ProblemDetailsErrorHandlingConfiguration里面又返回了 --> ProblemDetailsExceptionHandler

@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)ProblemDetailsExceptionHandler 是一个 @ControllerAdvice集中处理系统异常
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
    })

例子: 出现Method Not Allowed 异常:
1)不开启Problemdetails的时候,默认响应错误的json。状态码 405

{
    "timestamp": "2023-04-18T11:13:05.515+00:00",
    "status": 405,
    "error": "Method Not Allowed",
    "trace": "org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' is not supported\r\n\tat org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:265)\r\n\tat org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:441)\r\n\tat org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:382)\r\n\tat org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:126)\r\n\tat org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:68)\r\n\tat org.springframework.web.servlet.handler.",
    "message": "Method 'POST' is not supported.",
    "path": "/list"
}

2)开启ProblemDetails返回, 使用新的MediaType
返回的Content-Type是application/problem+json,而且可以自己扩展返回的数据

{
    "type": "about:blank",
    "title": "Method Not Allowed",
    "status": 405,
    "detail": "Method 'POST' is not supported.",
    "instance": "/list"
}

函数式Web:
SpringMVC 5.2 以后 允许我们使用函数式的方式,定义Web的请求处理流程。
Web请求处理的方式:
1.以前使用@Controller + @RequestMapping:耦合式 (路由、业务耦合)
2.现在可以使用函数式Web:分离式(路由、业务分离)

使用函数式Web的步骤:
1.实现配置类给容器中放RouterFunctions bean
2.每个业务准备一个自己的Handler


/**
 * 场景: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();
    }

实现Handler:

/**
 * @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();
    }
}

4. GraalVM 与 AOT - 将应用编译成可执行文件,飞速运行

====
Complier 与 Interpreter对比
AOT 与 JIT 对比

====
jvm执行java代码流程: jvm里面会判断一段代码是解释执行还是编译执行,如果是编译执行,就编译成机器码并且放到缓存里面,下次用到的时候,直接取;如果是解释执行,就直接解释执行,并且统计解释执行的次数,当次数达到某个阈值的时候,就触发编译,将机器猫放在缓存中
在这里插入图片描述
更详细的图:
方法执行的时候,判断是否已经有了编译好的机器码,如果是,直接从缓存中取出来执行;如果不是,进行热点探测,统计热点代码执行次数,是否超过阈值(这个阈值可以通过compileThreshold设置),
没有超过就解释执行,超过了就进行编译,编译的时候可以设置是否同步编译,如果是同步编译就是先编译好了再执行,非同步编译就是先解释执行完这块代码,然后提交一个编译请求,最后将编译好的机器码放在缓存中
在这里插入图片描述

====
(了解)JVM编译器: C1和C2

(了解)分层编译: Java 7开始引入了分层编译(Tiered Compiler)的概念
总的来说,C1的编译速度更快,C2的编译质量更高,分层编译的不同编译路径,也就是JVM根据当前服务的运行情况来寻找当前服务的最佳平衡点的一个过程。从JDK 8开始,JVM默认开启分层编译。

====
存在的问题:
1.java应用如果用jar,解释执行,热点代码才编译成机器码;初始启动速度慢,初始处理请求数量少。
2.大型云平台,要求每一种应用都必须秒级启动。每个应用都要求效率高。
希望的效果:
1.java应用也能提前被编译成机器码,随时急速启动,一启动就急速运行,最高性能
2.编译成机器码的好处:
1)另外的服务器还需要安装Java环境
2)编译成机器码的,可以在这个平台 Windows X64 直接运行。

====
原生镜像概念:native-image(就是编译成机器码、本地镜像)
1.最终的目标: 把应用打包成能适配本机平台的可执行文件(机器码、本地镜像)

GraalVM
https://www.graalvm.org/
GraalVM是一个高性能的JDK,旨在加速用Java和其他JVM语言编写的应用程序的执行,同时还提供JavaScript、Python和许多其他流行语言的运行时
GraalVM提供了两种运行Java应用程序的方式:
1.在HotSpot JVM上使用Graal即时(JIT)编译器 --> 和C2编译器类似,具有C2编译器的功能,常用于代替C2,一般不用,常见的jvm实现里面的C2已经很好了
2.作为预先编译(AOT)的本机可执行文件运行(本地镜像)。 --> 将程序编译成本机可执行文件
GraalVM的多语言能力使得在单个应用程序中混合多种编程语言成为可能,同时消除了外部语言调用的成本。

GraalVM基于HotSpot,替换了里面的编译器,不仅支持java系列的语言,还想要支持其它的语言,比如js,python等
在这里插入图片描述

====
跨平台提供原生镜像原理
GraalVM提供native-image工具,native-image工具使用不同平台上的编译工具,将你的应用编译成可执行文件(比如windows的.exe),然后这些可执行文件就能够在相同平台的不同机器上跑了
在这里插入图片描述
详细步骤参考雷老师的笔记

native-image可以本地安装然后编译jar包到可执行文件,springBoot也集成了,既然本地能够将应用编译成可执行文件了,为什么springBoot还要额外支持呢?
1.动态能力损失: 运行时才能确定的代码
并不是所有的Java代码都能支持本地打包,例如反射的代码(反射动态获取构造器,反射创建对象,反射调用一些方法),需要做一些额外处理,告诉graalvm反射会用到哪些方法、构造器
SpringBoot做了这部分: 它提供了一些注解:提前告知 graalvm 反射会用到哪些方法、构造器
2.配置文件损失 --> 配置文件时放在jar包内的,在编译成可执行文件的时候,配置文件不能被编译放在最后的可执行文件中
SpringBoot做了这部分: 额外处理(配置中心):提前告知 graalvm 配置文件怎么处理

不是所有的代码都能打包编译: 二进制里面不能包含的,不能动态的都得提前处理 --> SpringBoot都做好了

/**
 * 打包成本地镜像:
 *
 * 1、打成jar包:  注意修改 jar包内的 MANIFEST.MF 文件,指定Main-Class的全类名
 *        - java -jar xxx.jar 就可以执行。
 *        - 切换机器,安装java环境。默认解释执行,启动速度慢,运行速度慢
 * 2、打成本地镜像(可执行文件):
 *        - native-image -cp  你的jar包/路径  你的主类  -o 输出的文件名
 *        - native-image -cp boot3-15-aot-common-1.0-SNAPSHOT.jar com.atguigu.MainApplication -o Demo
 *
 * 并不是所有的Java代码都能支持本地打包;
 * SpringBoot保证Spring应用的所有程序都能在AOT的时候提前告知graalvm怎么处理?
 *
 *   - 动态能力损失:反射的代码:(动态获取构造器,反射创建对象,反射调用一些方法);
 *     解决方案:额外处理(SpringBoot 提供了一些注解):提前告知 graalvm 反射会用到哪些方法、构造器
 *   - 配置文件损失:
 *     解决方案:额外处理(配置中心):提前告知 graalvm 配置文件怎么处理
 *   - 【好消息:新版GraalVM可以自动进行预处理,不用我们手动进行补偿性的额外处理。】
 *   二进制里面不能包含的,不能动态的都得提前处理;
 *
 *   不是所有框架都适配了 AOT特性;Spring全系列栈适配OK
 *
 *  application.properties
 *  a(){
 *      //ssjsj  bcde();
 *      //提前处理
 *  }
 */

详细步骤参考雷老师的笔记

两条命令:
1、运行aot提前处理命令:mvn springboot:process-aot --> IDEA meavn插件里面也有
2、运行native打包:mvn -Pnative native:build --> IDEA meavn插件里面也有

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1215876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

俄罗斯方块小游戏

框架 package 框架;import java.awt.image.BufferedImage; import java.util.Objects;/*** author xiaoZhao* date 2022/5/7* describe* 小方块类* 方法&#xff1a; 左移、右移、下落*/ public class Cell {// 行private int row;// 列private int col;private BufferedIm…

kubernetes集群编排——etcd

备份 从镜像中拷贝etcdctl二进制命令 [rootk8s1 ~]# docker run -it --rm reg.westos.org/k8s/etcd:3.5.6-0 sh 输入ctrlpq快捷键&#xff0c;把容器打入后台 获取容器id [rootk8s1 ~]# docker ps 从容器拷贝命令到本机 docker container cp c7e28b381f07:/usr/local/bin/etcdc…

python爬虫概述及简单实践:获取豆瓣电影排行榜

目录 前言 Python爬虫概述 简单实践 - 获取豆瓣电影排行榜 1. 分析目标网页 2. 获取页面内容 3. 解析页面 4. 数据存储 5. 使用代理IP 总结 前言 Python爬虫是指通过程序自动化地对互联网上的信息进行抓取和分析的一种技术。Python作为一门易于学习且强大的编程语言&…

mysql数据模型

创建数据库 命令 create database hellox &#xff1a; &#xff08; hellox名字&#xff09; sql语句 创建 数据库 命令 create database hell&#xff1b; 也是创建但是有数据库不创建 命令 create database if not exists hell ; 切换数据库 命令 use hello&…

Facebook内容的类型

随着人们日益依赖的社交媒体来进行信息获取与交流&#xff0c;Facebook作为全球最大的社交媒体平台之一&#xff0c;那么Facebook的内容都有哪些类型呢&#xff1f;下面小编来讲讲吧&#xff01; 1、实时发生的事 我们需要实时了解时事动态&#xff0c;这样可以使用户对品牌发…

android PopupWindow设置

记录一个小功能&#xff0c;使用场景&#xff0c;列表项点击弹出 如图&#xff1a; java类代码&#xff1a; public class PopupUtil extends PopupWindow {private Activity context;private View view;private ListView listView;private TextView m_tv_reminderm, m_tv_Wa…

React-Router源码分析-History库

history源码 history 在 v5 之前使用单独的包&#xff0c; v6 之后再 router 包中单独实现。 history源码 Action 路由切换的动作类型&#xff0c;包含三种类型&#xff1a; POPREPLACEPUSH Action 枚举&#xff1a; export enum Action {Pop "POP",Push &quo…

BI 数据可视化平台建设(2)—筛选器组件升级实践

作者&#xff1a;vivo 互联网大数据团队-Wang Lei 本文是vivo互联网大数据团队《BI数据可视化平台建设》系列文章第2篇 -筛选器组件。 本文主要介绍了BI数据可视化平台建设中比较核心的筛选器组件&#xff0c; 涉及组件分类、组件库开发等升级实践经验&#xff0c;通过分享一些…

Redis分布式锁(上)

不论面试还是实际工作中&#xff0c;Redis都是避无可避的技术点。在我心里&#xff0c;MySQL和Redis是衡量一个程序员是否“小有所成”的两把标尺。如果他能熟练使用MySQL和Redis&#xff0c;以小化大&#xff0c;充分利用现有资源出色地完成当下需求&#xff0c;说明他已经成长…

性能测试知多少---系统架构分析

之前有对性能需求进行过分析&#xff0c;那篇主要从项目业务、背景等角度如何抽丝剥茧的将项目的需求抽离出来。在我们进行需求的时候也需要对被测项目的架构有一定的认识&#xff0c;如果不了解被测系统的架构&#xff0c;那么在后期的性能分析与调优阶段将无从下手。 简单系…

亚马逊EC2服务器搭建Linux系统宝塔环境

目录 &#x1f4dd;摘要 &#x1f4a1;引言 一. 购买亚马逊服务器EC2 二. 安装Linux系统 三. 在终端安装宝塔 3.1 安装宝塔 3.2安装成功 四. 配置宝塔 五 应用场景 六 代码案例演示 七 为什么选择亚马逊EC2服务器部署&#xff1f; &#x1f4aa; 可靠性和高可用性 灵…

jff2文件系统(一)

jff2概述 JFFS2全称jouranlling Flash File System Version2,即日志文件系统&#xff0c;是Redhat公司开发的开源闪存文件系统&#xff0c;其前身是JFFS, 最早只支持NOR Flash, 自2.6版以后开始支持NAND Flash&#xff0c; 在闪存上使用非常广泛&#xff0c;同时在嵌入式系统中…

ChatGPT Plus暂停注册,用户激增压力太大!

11月15日&#xff0c;OpenAI联合创始人兼首席执行官Sam Altman在社交平台宣布&#xff0c;暂停ChatGPT Plus注册。 Sam表示&#xff0c;在首次开发者大会上发布了自定义GPT、GPT-4 Turbo等一系列重磅产品后&#xff0c;用户激增对服务器产生了巨大压力&#xff0c;不得已才做出…

Java 各种工具类的使用方法

1. 属性拷贝 属性名词和类型相同才能拷贝 import org.springframework.beans.BeanUtils; BeanUtils.copyProperties(dto,wmNews); //dto, wmNews 是两个实体类 dto为源对象&#xff0c;wmNews为目标对象2. list集合转换为string类型 import org.apache.commons.lang3.String…

分布式教程从0到1【1】分布式基础

1 分布式基础概念 1.1 微服务 微服务架构风格&#xff0c;就像是把一个单独的应用程序开发为一套小服务&#xff0c;每个小服务运行在自己的进程中&#xff0c;并使用轻量级机制通信&#xff0c;通常是 HTTP API。这些服务围绕业务能力来构建&#xff0c;并通过完全自动化部署…

ECRS工时分析软件:全面提升生产效率和产能管理的利器

在当今高度竞争的商业环境中&#xff0c;企业需要不断提升生产效率和产能管理以保持竞争优势。ECRS工时分析软件作为一款专业的工具&#xff0c;通过自动导出各种表格和图表&#xff0c;全面涵盖了生产过程中的各种分析和改善活动&#xff0c;为企业提供了提升生产效率和产能管…

数据库.创建表

创建表结构 -- 创建表结构create table tb_user(id int comment ID,唯一标识,username varchar(20) comment 用户名,name varchar(10) comment 姓名,gae int comment 年龄,gender char(1) comment 性别)comment 用户表;

Freeswitch中CHANNEL_HANGUP外呼挂断事件

1.CHANNEL_HANGUP外呼挂断事件 事件详细 ################## 外呼挂断&#xff1a;############################# [EslMessage{contentTypecommand/reply, headers3, body0 lines}] 2023-11-16T03:41:33.5140800 INFO c.e.c.v.s.c.i.FsServerEventHandler - eventReceived:…

洗地机哪个牌子好?2023热门洗地推荐

随着科技的不断发展&#xff0c;智能家居产品成为现代生活的一部分。在这个日新月异的时代&#xff0c;人们追求更便捷、高效的生活方式。洗地机作为一款时尚生活必备的清洁家电产品&#xff0c;正逐渐受到人们的关注和喜爱&#xff0c;面对满目琳琅的洗地机&#xff0c;我们该…

京东联盟flutter插件使用方法

目录 1.京东联盟官网注册申请步骤略~2.安卓端插件配置&#xff1a;3.IOS端插件配置4.其它配置5.京东OAuth授权 文档地址&#xff1a;https://baiyuliang.blog.csdn.net/article/details/134444104 京东联盟flutter插件地址&#xff1a;https://pub.dev/packages/jdkit 1.京东联…