目录
- Java 版本要求
- Spring Framework 版本
- GraalVM 支持和原生镜像
- 错误信息返回新格式
- 函数式编程
- 案例:
- 响应式编程
- 自动配置包位置变化
- jakata api迁移
- 配置属性兼容性
- Apache HttpClient 4 的依赖管理
- Servlet 和过滤器注册
- Git 提交 ID Maven 插件版本属性
- 增强服务连接
Java 版本要求
- Spring Boot 3.x 要求至少使用 Java 17,这是最低版本要求。
- 同时,Spring Boot 3.x 也已经通过了 Java 19 的测试,确保了更好的兼容性和性能。
- 这意味着开发者需要使用 Java 17 或更高版本来运行和开发基于 Spring Boot 3.x 的应用程序。
Spring Framework 版本
- Spring Boot 3.x 基于最新的 Spring Framework 6 构建,提供了更好的性能和功能。
- 这是对之前 Spring Boot 2.x 使用的 Spring Framework 5.x 的一个重大升级。
GraalVM 支持和原生镜像
Spring Boot 3.x 引入了对 GraalVM 的支持,允许开发者使用 GraalVM 将 Spring 应用程序编译成本地可执行的镜像文件。
这可以显著提升应用程序的启动速度、峰值性能以及减少内存使用。
这一特性取代了之前的 Spring Native 项目。
错误信息返回新格式
错误信息返回新格式,使用方式:在配置文件中开启即可
spring:
mvc:
problemdetails:
enabled: true
开启后的区别:对于这些异常
@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
})
-
springboot2.x版本会返回这样的数据
{ "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.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:505)\r\n\tat org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1275)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1057)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)\r\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:563)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)\r\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:631)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:833)\r\n", "message": "Method 'POST' is not supported.", "path": "/list" }
-
springboot3.x开启后返回这样的数据
{
"type": "about:blank",
"title": "Method Not Allowed",
"status": 405,
"detail": "Method 'POST' is not supported.",
"instance": "/list"
}
函数式编程
SpringMVC 5.2 以后 允许我们使用函数式的方式,定义Web的请求处理流程。
函数式接口,Web请求处理的方式:
- @Controller + @RequestMapping:耦合式 (路由、业务耦合)
- 函数式Web:分离式(路由、业务分离)
案例:
- GET /user/1 :获取1号用户
- GET /users :获取所有用户
- POST /user :请求体携带JSON,新增一个用户
- PUT /user/1 :请求体携带JSON,修改1号用户
- DELETE /user/1 :删除1号用户
自定义配置类
@Configuration(proxyBeanMethods = false)
public class MyRoutingConfiguration {
private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);
@Bean
public RouterFunction<ServerResponse> routerFunction(MyUserHandler userHandler) {
return route()
.GET("/{user}", ACCEPT_JSON, userHandler::getUser)
.GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
.DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
.build();
}
}
自定义Handler类,函数式编程
@Component
public class MyUserHandler {
public ServerResponse getUser(ServerRequest request) {
...
return ServerResponse.ok().build();
}
public ServerResponse getUserCustomers(ServerRequest request) {
...
return ServerResponse.ok().build();
}
public ServerResponse deleteUser(ServerRequest request) {
...
return ServerResponse.ok().build();
}
}
响应式编程
案例:响应式编程实现远程调用(RPC)。两种实现方式
- 第一种webclient。
- 第二种HTTP Interface,Spring 允许我们通过定义接口的方式,给任意位置发送 http 请求,实现远程调用,可以用来简化 HTTP 远程访问。需要webflux场景才可以
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
接口
public interface UserService {
@GetExchange(url = "/user/list")//这里设置需要给哪个地址发送http请求
String search(@RequestParam("keyword ") String keyword , @RequestHeader("auth") String headerStr);//把keywaord的值当作发http请求的参数q的值
}
测试
@Test
void contextLoads() throws InterruptedException {
//1、创建客户端
WebClient client = WebClient.builder()
.baseUrl("http://localhost:9090")
.codecs(clientCodecConfigurer -> {
clientCodecConfigurer
.defaultCodecs()
.maxInMemorySize(256*1024*1024);
//响应数据量太大有可能会超出BufferSize,所以这里设置的大一点
})
.build();
//2、创建工厂
HttpServiceProxyFactory factory = HttpServiceProxyFactory
.builder(WebClientAdapter.forClient(client)).build();
//3、获取代理对象
UserService userService = factory.createClient(UserService.class);
//4、测试调用
Mono<String> search = userService.search("email");
System.out.println("==========");
search.subscribe(str -> System.out.println(str));
Thread.sleep(100000);
}
自动配置包位置变化
SpringBoot3:现在在这里了: META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
jakata api迁移
比如servlet的包,在boot3.0引用的是jakata.servlet-api,在之前的比如druid是javax.servlet-api
配置属性兼容性
- 在 Spring Boot 3.x 中,一些配置属性被重新命名或删除,开发人员需要更新 application.properties 或 application.yml 配置文件。
- 为了帮助开发者进行升级,Spring Boot 提供了 spring-boot-properties-migrator 模块,该模块可以在启动时分析应用程序的环境并打印诊断结果,同时在运行时为开发者临时迁移属性
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
Apache HttpClient 4 的依赖管理
- Spring Framework 6 中删除了RestTemplate对Apache HttpClient 4 的支持,取而代之的是 Apache HttpClient 5。
- Spring Boot 3.0 包括 HttpClient 4 和 5 的依赖管理。继续使用 HttpClient 4
HttpClient 5 的依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1</version>
</dependency>
//创建 HttpClient 实例
HttpClient httpClient = HttpClientBuilder.create().build();
//创建 HttpGet 请求
HttpGet httpGet = new HttpGet("https://www.example.com/");
//发送请求并获取响应
HttpResponse response = httpClient.execute(httpGet)
//处理响应
//其中,response.getStatusLine().getStatusCode() 可以获取响应状态码,
//EntityUtils.toString(response.getEntity()) 可以获取响应正文。
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
完整代码
作者:哪吒编程
链接:https://www.zhihu.com/question/575241602/answer/3220075536
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
public class HttpClientExample {
public static void main(String[] args) throws Exception {
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet("https://www.example.com/");
HttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println("Status code: " + statusCode);
System.out.println("Response body: " + responseBody);
}
}
Servlet 和过滤器注册
- ServletRegistrationBean如果注册失败,和类FilterRegistrationBean现在将失败,IllegalStateException而不是记录警告。
- 如果需要旧的行为,应该调用setIgnoreRegistrationFailure(true)你的注册 bean。
Git 提交 ID Maven 插件版本属性
- 用于覆盖 的版本的属性io.github.git-commit-id:git-commit-id-maven-plugin已更新以与其工件名称保持一致。
- 为了适应这种变化,请git-commit-id-plugin.version在git-commit-id-maven-plugin.version你的pom.xml。
增强服务连接
- 引入了新的服务连接概念。此类连接在应用程序中由 bean 表示ConnectionDetails。
- 这些 bean 提供了必要的细节来建立与删除服务的连接,并且 Spring Boot 的自动配置已更新为使用ConnectionDetailsbean。
- 当此类 beans 可用时,它们将优先于任何与连接相关的配置属性。与连接本身无关的配置属性,
- 例如控制连接池大小和行为的属性,仍将被使用。
- 此低级功能旨在作为其他高级功能的构建块,这些功能通过定义ConnectionDetailsbean 自动配置服务连接。
- 在没有在其他地方定义适当的 bean 的情况下…ConnectionDetails,Spring Boot 的自动配置已更新为定义自己的基础,由相关配置属性支持。
- 这允许…ConnectionDetails注入而不必处理没有这样的 bean 可用并且需要回退到基于属性的配置的情况。