jdbc通过spi机制自动加载驱动:drivermanager启动时调用serviceloader.load(driver.class),利用tccl解析meta-inf/services/java.sql.driver文件,加载并执行驱动静态块注册;注册对象跨bootstrap与appclassloader持有,最终由acceptsurl匹配生效驱动。

JDBC 在底层通过 SPI(Service Provider Interface)机制自动加载不同厂商的数据库驱动,核心在于“约定优于配置”和运行时动态发现——不写死类名、不手动调用 Class.forName(),而是靠标准文件路径 + 标准加载器协作完成。
驱动发现靠 META-INF/services/java.sql.Driver 文件
每个数据库驱动 JAR 包(如 mysql-connector-java-8.0.33.jar)必须在 META-INF/services/ 目录下提供一个纯文本文件,文件名严格为:
java.sql.Driver
该文件内容是驱动实现类的全限定名,例如:
com.mysql.cj.jdbc.Driver
多个驱动可共存,每行一个类名;JDK 的 ServiceLoader 会按顺序读取并尝试加载这些类。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
DriverManager 启动时触发 ServiceLoader 加载
当应用首次调用 DriverManager.getConnection(...) 时,DriverManager 内部会执行:
-
ServiceLoader.load(Driver.class)—— 这是 SPI 的标准入口 - 默认使用当前线程的上下文类加载器(TCCL),通常是应用类加载器(AppClassLoader)
- TCCL 负责定位 classpath 下所有
META-INF/services/java.sql.Driver文件 - 逐个解析文件内容,用 TCCL 加载对应类(如
com.mysql.cj.jdbc.Driver)
驱动注册发生在静态块中,跨加载器持有实例
被加载的驱动类(如 MySQL 的 Driver)通常包含静态初始化块:
static { DriverManager.registerDriver(new Driver()); }
这里发生关键协作:
-
new Driver()实例由 AppClassLoader 创建 -
DriverManager.registerDriver(...)方法由 Bootstrap ClassLoader 提供(来自java.base) -
DriverManager内部用Vector<driverinfo></driverinfo>存储引用,容器在 Bootstrap 空间,但元素指向 AppClassLoader 加载的对象 - 这就实现了“接口与实现跨加载器共存”,靠的是对象引用传递,而非类可见性
连接时由 URL 触发匹配,非全部驱动都生效
加载 ≠ 生效。真正决定哪个驱动干活的是 acceptsURL(String url) 方法:
-
DriverManager拿到所有已注册驱动,逐个调用driver.acceptsURL("jdbc:mysql://...") - 只有返回
true的驱动才参与后续连接流程 - MySQL 5.x 和 8.x 驱动支持的 URL 前缀不同(
jdbc:mysql:vsjdbc:mysql:aurora:),所以换版本后连不上,往往不是没加载,而是没匹配上
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










