1、简介 在 Spring Boot 中整合 MySQL 时,我们通常依赖 Spring Boot 的自动配置和 JDBC 支持来连接数据库。不过,遇到配置问题的情况并不少见,尤其是在使用 过时的依赖 时。其中一个异常就是:
Cannot load driver class: com.mysql.jdbc.Driver 本文将带你了解出现 “Cannot load driver class: com.mysql.jdbc.Driver” 异常的原因以及解决办法。
2、理解原因 这个问题的根源在于使用了过时的 MySQL 驱动程序类。在早期版本的 MySQL JDBC 驱动程序 (Connector/J) 中,通常使用以下驱动程序类:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver 不过,从 MySQL Connector/J 8.0 开始,该类已被弃用并删除。更新后的驱动程序类是
com.mysql.cj.jdbc.Driver 如果在新版本的 MySQL 驱动程序中继续使用旧的类名,应用将无法启动,并出现 ClassNotFoundException 异常。
3、处理问题 要解决这个问题,需要更新 Spring Boot 配置和项目中使用的依赖。
3.1、使用正确的依赖 第一步是在 application.properties 或 application.yml 文件中新的驱动程序类替换旧的驱动程序类。
spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=secret # 新的驱动类 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 或者 application.yml 文件:
spring: datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: secret driver-class-name: com.
🐞 Bug 修复 由于目录权限问题,使用原生镜像容器映像在 podman 上构建 Spring Boot 失败 #45256 Neo4jReactiveDataAutoConfiguration 假定某些 Bean 可用 #45235 使用空数据库名称时出现错误的 jOOQ 异常翻译 #45219 MessageSourceMessageInterpolator 不会在 message 与其 code 匹配时替换参数 #45213 IntegrationMbeanExporter 不符合由所有 BeanPostProcessors 处理的条件,使用 JMX 时会显示警告 #45194 OAuth2AuthorizationServerJwtAutoConfiguration 错误地使用了 @ConditionalOnClass #45178 MongoDB 的依赖管理缺少 Kotlin coroutine 驱动模块 #45159 ImagePlatform 可能导致 “OS must not be empty” 的 IllegalArgumentException #45153 TypeUtils 无法处理不同位置上名称相同的泛型 #45039 HttpClient 5 5.4.3 会中断本地 Docker transport #45028 不能使用 spring.datasource.hikari.data-source-class-name,因为驱动程序类名总是必需的,而 Hikari 不同时接受这两个名称。 #45002 如果 JDBC URL 用于未知驱动程序,则应用自定义 JdbcConnectionDetails 的后处理会在 Hikari 中触发 NPE #44998 在 Hikari 中,当尝试使用未知驱动程序的 JDBC URL 构建数据源时,DataSourceBuilder 会触发 NPE。 #44995 SSL 配置不监控链接文件的更改 #44887 EmbeddedLdapAutoConfiguration 不应依赖于 PreDestroy #44874 DataSourceTransactionManagerAutoConfiguration 应在 DataSourceAutoConfiguration 之后运行 #44819 JsonValueWriter 会对深度嵌套的项目抛出 StackOverflowError 错误#44627 在响应式 web 应用中,如果不使用 ‘file:’ 前缀,SslBundle 将无法打开 store 文件位置 #44535 使用结构化日志记录 Path 对象抛出 StackOverflowError #44507 📔 文档 将 @Component 设为 javadoc 链接 #45258 修复指向 buildpacks.
1、简介 本文将带你了解 @EnableEurekaClient 与 @EnableDiscoveryClient 的区别。
这俩注解在 Spring Cloud 微服务应用中,都用于客户端发现。
2、微服务中的服务注册 在以分布式和松散耦合为特点的微服务领域,随着服务数量的增加,维护准确的服务列表并确保它们之间的无缝通信变得越来越复杂。手动跟踪服务的健康状况和可用性是一项资源密集且容易出错的工作。这时,服务注册中心就变得非常有用。
服务注册中心是一个保存可用服务信息的数据库。它是服务注册、查询和管理的中心点。
当微服务启动时,它会在服务注册中心中注册自己。
3、@EnableDiscoveryClient 注解 @EnableDiscoveryClient 是 Spring Boot 提供的一种更通用的注解,使其成为服务发现的灵活选择。
可以将其视为一种约定,它允许我们的应用现在和将来与不同的服务注册中心协同工作。它包含在 spring-cloud-commons 依赖中,成为 Spring Cloud 服务发现机制的核心部分。
但是,它并不能独立工作,实际运行时需要真正的实现,如 Eureka、Consul 或 Zookeeper。
4、@EnableEurekaClient 注解 Eureka 最初由 Netflix 开发,提供了一个强大的服务发现解决方案。Eureka 客户端是 Eureka 的基本组成部分。
具体来说,应用可以作为客户端,在使用 Eureka 实现的服务注册中心注册。此外,Spring Cloud 还为其提供了一个抽象层,与 Spring Boot 结合使用,可大大简化 Eureka 与微服务架构的集成,从而提高开发人员的工作效率。
@EnableEurekaClient 注解在这一过程中起着至关重要的作用。更确切地说,它是作为客户端的服务向服务注册中心注册时使用的注解之一。
4.1、实现 Eureka Client 只有当 pom.xml 中包含 Eureka 客户端依赖 时,Eureka 客户端才能工作:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> 还要定义 spring-cloud-commons <dependencyManagement>:
<dependencyManagement> <dependencies> <dependency> <groupId>org.
功能特点 简化多表操作:MyBatis-Plus-Join 是 MyBatis-Plus 的扩展,让开发者能更便捷地进行多表关联查询、子查询等操作,通过简洁的API满足复杂查询需求。例如,在进行多表联合查询时,无需编写大量复杂的SQL语句或配置文件,只需简单配置和调用相关方法,即可实现多表数据的关联查询。 支持多种特性:支持列枚举、别名、逻辑删除、TypeHandle、一对一、一对多等功能,还支持 Lambda 和字符串两种查询方式,以及自定义字段映射和结果转换、动态条件构造和链式调用等高级特性。比如,在进行数据查询时,可以根据不同的条件动态构造查询语句,灵活地实现各种复杂的查询逻辑。 兼容性好:作为 MyBatis-Plus 的插件,它完全兼容 MyBatis-Plus 的使用习惯,引入后不会对现有工程产生影响,能与 MyBatis-Plus 原有功能无缝集成。 依赖配置 以Maven项目为例,在pom.xml文件中添加以下依赖即可使用:
<dependency> <groupId>com.github.yulichang</groupId> <artifactId>mybatis-plus-join-boot-starter</artifactId> <version>1.5.3</version> </dependency> 最新版 MyBatis-Plus-Join 需要配合 MyBatis-Plus 3.1.2 及以上的版本使用。
代码示例 假设存在用户表 user 和订单表 order,它们之间通过 user_id 关联,以下是使用 mybatis-plus-join-boot-starter 进行多表查询的示例:
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.yulichang.base.MPJBaseMapper; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.example.demo.entity.User; import com.example.demo.entity.Order; import org.springframework.stereotype.Repository; import javax.annotation.Resource; import java.util.List; @Repository public class UserRepository { @Resource private MPJBaseMapper<User> userMapper; public List<User> getUserWithOrders() { // 使用MPJLambdaWrapper进行多表查询 MPJLambdaWrapper<User> wrapper = new MPJLambdaWrapper<User>() .
1、概览 默认情况下,Spring Boot 提供嵌入式 Tomcat 服务器,但在某些情况下,我们可能希望根据应用的需求来禁用/启用它。
对于不需要 Web 服务的 Spring Boot 应用,禁用 Tomcat 可以节省资源。
2、理解 Spring Boot 中的嵌入式 Tomcat Spring Boot 在应用的可执行 JAR 文件中捆绑了嵌入式 Tomcat 服务器,从而简化了应用的部署。这种方法消除了安装和配置外部 Tomcat 实例的需要,使开发和部署更加高效。
Spring Boot 使用 Spring Boot Starter 来包含嵌入式 Tomcat 的必要依赖。默认情况下, spring-boot-starter-web Starter 会在 Tomcat 出现在 classpath 中时自动配置和初始化 Tomcat。
2.1、嵌入式 Tomcat 的优势 Spring Boot 的嵌入式 Tomcat 服务器具有多种优势:
简化部署:无需安装外部 Tomcat 服务器。 独立的应用:应用程序可打包为 JAR 文件,在任何地方运行。 自动配置:Spring Boot 根据依赖自动配置 Tomcat。 灵活:可轻松替换为 Jetty 或 Undertow 等其他嵌入式服务器。 2.2、为什么要禁用 Tomcat 服务器? 虽然嵌入式 Tomcat 很有用,但在某些情况下,禁用它对我们也有好处:
本文将带你了解如何在 Spring Boot 中使用 spring-ai 无缝接入 DeepSeek 和通义千问来构建自己的 AI 应用。
Spring & JDK 版本:
springboot 3.4.3 jdk17 1、maven依赖 <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency> 2、application.yaml 配置 # DeepSeek 配置,完全兼容openai配置 # spring: # ai: # openai: # base-url: https://api.deepseek.com # DeepSeek的OpenAI式端点 # api-key: sk-xxxxxxxxx # chat.options: # model: deepseek-chat # 指定DeepSeek的模型名称 # 通义千问配置 spring: ai: openai: base-url: https://dashscope.aliyuncs.com/compatible-mode # 通义千问 api-key: sk-xxxxxxxxxxx chat.options: model: qwen-plus 3、Controller package org.example.springboot3ds.controller; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import org.
1、概览 HTTP/2 是广泛使用的 HTTP/1.1 协议的后续协议,它通过采用多路复用和 Header 压缩等新功能提高了网络性能。
本文将带你了解如何配置 Spring Boot 应用,以在嵌入式 Tomcat 服务器上启用 HTTP/2。
2、HTTP/2 超文本传输协议(HTTP)是一种在互联网上获取资源的应用协议。HTTP/1.1 于 1997 年 1 月发布,二十多年来为大多数网络提供服务。该版本发现了在某些情况下导致性能缓慢的问题。
HTTP/2 克服了 HTTP/1.1 中的性能问题,具有以下特点:
多路复用 - HTTP/1.1 使用多个连接发送多个请求;多路复用允许通过单个连接发送请求,从而减少资源消耗和延迟 Header 压缩 - 如果不进行压缩,由于 TCP 启动速度较慢,通常需要多次往返才能发送 Header;压缩 Header 后,Header 的发送往返次数会减少,大部分时间都能在一次往返内完成 二进制 - 与使用文本编码数据的 HTTP/1.1 相比,HTTP/2 以二进制格式发送数据,以减少解析开销并缩小报文大小。 3、先决条件 HTTP/2 可以通过明文或 TLS 运行。大多数 Web 浏览器不支持明文 HTTP/2,因此建议通过 TLS 运行。
首先要在嵌入式 Web 服务器上启用 SSL。
在控制台中运行以下 keytool 命令来生成一个 keystore,用于存储 SSL/TLS 使用的密钥和证书,并将其放入嵌入式 Tomcat 中。
$ keytool -genkeypair -alias http2-alias -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.
🐞 Bug 修复 logging.structured.json.customizer 的属性元数据类型不正确 #43916 仅指定 logging.structured.gelf.host 时,GraylogExtendedLogFormatProperties 会抛出 NullPointerException 异常 #43863 结构化日志属性在 Native Image 中不起作用 #43862 当 ALLOW_EMPTY_PASSWORD=yes 时,ClickHouse 的 Docker Compose 支持不允许使用空密码 #43790 在 2.23 或更早版本中,docker compose ps 现在会因为未知的 --orphans flag 而失败 #43717 构建信息时间戳被截断为秒 #43617 用于 SSL 重载的 FileWatcher 不支持 Symlink #43604 BindableRuntimeHintsRegistrar 应处理 TypeNotPresentException #43600 使用 Log4J2 StatusLogger 时,CapturedOutput 为空 #43578 Spring Boot 3.4 与 Gson 2.1 不兼容 #43442 使用 JUnit 测试依赖 spring-boot-actuator-autoconfigure 但不依赖 org.junit.platform:junit-platform-launcher 的 Gradle 7.
1、概览 在分布式系统和微服务架构中,优雅地处理故障对于保持系统可靠性和性能至关重要。断路器(Circuit Breaker,也称为熔断器)和重试(Retry)是有助于实现这一目标的两种基本弹性模式。虽然这两种模式都旨在提高系统的稳定性和可靠性,但它们的目的截然不同,适用于不同的场景。
本文将带你深入了解这些模式,包括它们的机制、用例以及在 Spring Boot 中使用 Resilience4j 实现的细节。
2、什么是重试? 重试模式是一种简单而强大的机制,用于处理分布式系统中的瞬时故障。当操作失败时,重试模式会尝试多次执行相同的操作,希望临时问题能自行解决。
2.1、重试的主要特点 重试机制围绕特定属性展开,这些属性使重试机制能够有效处理瞬时问题,确保临时故障不会升级为重大问题:
重复尝试:核心理念是对失败的操作重新执行指定次数。 Backoff(回退)策略:这是一种高级的重试机制,其中包括退避策略,如指数退避,有助于避免对系统造成过大压力。 适用于临时故障:最适合处理间歇性网络问题、临时服务不可用或瞬间资源紧张的情况。 2.2、重试示例 来看一个使用 Resilience4j 实现重试机制的简单示例:
@Test public void whenRetryWithExponentialBackoffIsUsed_thenItRetriesAndSucceeds() { IntervalFunction intervalFn = IntervalFunction.ofExponentialBackoff(1000, 2); RetryConfig retryConfig = RetryConfig.custom() .maxAttempts(5) .intervalFunction(intervalFn) .build(); Retry retry = Retry.of("paymentRetry", retryConfig); when(paymentService.process(1)).thenThrow(new RuntimeException("First Failure")) .thenThrow(new RuntimeException("Second Failure")) .thenReturn("Success"); Callable<String> decoratedCallable = Retry.decorateCallable( retry, () -> paymentService.processPayment(1) ); try { String result = decoratedCallable.call(); assertEquals("Success", result); } catch (Exception ignored) { } verify(paymentService, times(3)).
1、概览 日志是任何软件应用程序的基本功能。它通过记录错误、警告和其他事件,帮助跟踪应用程序在运行期间的行为。
默认情况下,Spring Boot 应用程序会生成非结构化、人类可读的日志。虽然这些日志对开发人员很有用,但它们不容易被日志聚合工具解析或分析。结构化日志解决了这一限制。
本文将带你了解如何使用 Spring Boot 3.4.0 版中引入的功能实现结构化日志。
2、Maven 依赖 首先,在 pom.xml 中添加 spring-boot-starter 来启动 Spring Boot 项目:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>3.4.0</version> </dependency> 上述依赖为 Spring Boot 应用中的自动配置和日志记录提供了支持。
3、Spring Boot 默认的日志 以下是 Spring Boot 的默认日志:
INFO 22059 --- [ main] c.b.s.StructuredLoggingApp : No active profile set, falling back to 1 default profile: "default" INFO 22059 --- [ main] c.b.s.StructuredLoggingApp : Started StructuredLoggingApp in 2.349 seconds (process running for 3.259) 虽然这些日志信息量很大,但却无法被 Elasticsearch 等工具轻松抓取或进行指标分析。JSON 等结构化日志格式通过标准化日志内容解决了这一问题。