iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >如何使用springboot通过spi机制加载mysql驱动
  • 938
分享到

如何使用springboot通过spi机制加载mysql驱动

2023-06-20 18:06:59 938人浏览 薄情痞子
摘要

本篇内容介绍了“如何使用SpringBoot通过spi机制加载mysql驱动”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!SPI是一种jdk

本篇内容介绍了“如何使用SpringBoot通过spi机制加载mysql驱动”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

SPI是一种jdk提供的加载插件的灵活机制,分离了接口与实现,就拿常用的数据库驱动来说,我们只需要在spring系统中引入对应的数据库依赖包(比如Mysql-connector-java以及针对oracle的ojdbc6驱动),然后在yml或者properties配置文件中对应的数据源配置就可自动使用对应的sql驱动,

比如mysql的配置:

spring:  datasource:    url: jdbc:mysql://localhost:3306/xxxxx?autoReconnect=true&useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai    username: dev    passWord: xxxxxx    platfORM: mysql

spi机制正如jdk的classloader一样,你不引用它,它是不会自动加载到JVM的,不是引入了下面的的两个sql驱动依赖就必然会加载oracle以及mysql的驱动:

<!--oracle驱动-->        <dependency>            <groupId>com.oracle</groupId>            <artifactId>ojdbc6</artifactId>            <version>12.1.0.1-atlassian-hosted</version>        </dependency>         <!--mysql驱动-->        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <scope>runtime</scope>        </dependency>

正是由于jdk的这种spi机制,我们在spring项目中使用对应的驱动才这么简单,

我们只需做两件事:

在pom文件中引入对应的驱动依赖

在配置文件中配置对应的数据源即可

那么在spring项目中到底是谁触发了数据库驱动的spi加载机制呢?为了说明这个问题,咱们先说说jdk的spi的工作机制,jdk的spi通过ServiceLoader这个类来完成对应接口实现类的加载工作,就拿咱们要说的数据库驱动来说,

ServiceLoader会在spring项目的classpath中寻找那些满足下面条件的类:

这些jar包的META-INF/services有一个java.sql.Driver的文件

对应java.sql.Driver文件中为该数据库驱动对应的数据库驱动的实现类,比如mysql驱动对应的就是com.mysql.cj.jdbc.Driver,如下图所示:

如何使用springboot通过spi机制加载mysql驱动

JDK这部分有关SPI具体的实现机制可以阅读下ServiceLoader的内部类LazyIterator,该类的hasNextService、nextService两个方法就是具体SPI机制工作底层机制。

好了,上面简要概述了下JDK的SPI工作机制,下面继续看spring框架如何使用spi机制来完成数据库驱动的自动管理的(加载、注销),接下来就按照事情发展的先后的先后顺序把mysql驱动加载的全过程屡一下,笔者使用的是springboot 2.x,数据源使用的数据源为Hikari,这是后来居上的一款数据源,凭借其优秀的性能以及监控机制成为了springboot 2.x之后首推的数据源,

用过springboot的小伙伴对springboot的自动装载机制,数据源的配置也是使用的自动装配机制,

具体类DataSourceAutoConfiguration

如何使用springboot通过spi机制加载mysql驱动

注意上面标红部分,这里面引入的Hikari、Tomcat等(除了DataSourceJmxConfiguration之外)都是一些数据源配置,我们先看下

springboot推荐的Hikari数据源配置:

       @Configuration@ConditionalOnClass(HikariDataSource.class)@ConditionalOnMissingBean(DataSource.class)@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",matchIfMissing = true)static class Hikari { @Bean@ConfigurationProperties(prefix = "spring.datasource.hikari")public HikariDataSource dataSource(DataSourceProperties properties) {            // 使用配置文件中的数据源配置来创建Hikari数据源HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);if (StringUtils.hasText(properties.getName())) {dataSource.setPoolName(properties.getName());}return dataSource;} }

由于在DataSourceAutoConfiguration类中首先引入的就是Hikari的配置,DataSource没有创建,满足ConditionalOnMissingBean以及其他一些条件,就会使用该配置类创建数据源,好了接下来看下createDataSource到底是怎么创建数据源的,

这个过程又是怎么跟SPI关联起来的

abstract class DataSourceConfiguration { @SuppressWarnings("unchecked")protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {        //使用DataSourceProperties数据源配置创建DataSourceBuilder对象(设计模式中的建造者模式)return (T) properties.initializeDataSourceBuilder().type(type).build();}     //下面看下DataSourceBuilder的build方法    public T build() {        //在该例子中,type返回的是com.zaxxer.hikari.HikariDataSource类Class<? extends DataSource> type = getType();        //实例化HikariDataSource类DataSource result = BeanUtils.instantiateClass(type);maybeGetDriverClassName();        //bind方法中会调用属性的设置,反射机制,在设置driverClassName属性时bind(result);return (T) result;}     // HikariConfig的方法,HikariDataSource继承自HikariConfig类public void setDriverClassName(String driverClassName)   {      checkIfSealed();       Class<?> driverClass = null;      ClassLoader threadContextClassLoader = Thread.currentThread().getContextClassLoader();      try {         if (threadContextClassLoader != null) {            try {                //加载driverClassName对应的类,即com.mysql.cj.jdbc.Driver类,该类为mysql对应的驱动类               driverClass = threadContextClassLoader.loadClass(driverClassName);               LOGGER.debug("Driver class {} found in Thread context class loader {}", driverClassName, threadContextClassLoader);            }            catch (ClassNotFoundException e) {               LOGGER.debug("Driver class {} not found in Thread context class loader {}, trying classloader {}",                            driverClassName, threadContextClassLoader, this.getClass().getClassLoader());            }         }          if (driverClass == null) {            driverClass = this.getClass().getClassLoader().loadClass(driverClassName);            LOGGER.debug("Driver class {} found in the HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());         }      } catch (ClassNotFoundException e) {         LOGGER.error("Failed to load driver class {} from HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());      }       if (driverClass == null) {         throw new RuntimeException("Failed to load driver class " + driverClassName + " in either of HikariConfig class loader or Thread context classloader");      }       try {         // 创建com.mysql.cj.jdbc.Driver对象,接下来看下com.mysql.cj.jdbc.Driver创建对象过程中发生了什么         driverClass.newInstance();         this.driverClassName = driverClassName;      }      catch (Exception e) {         throw new RuntimeException("Failed to instantiate class " + driverClassName, e);      }   }  // com.mysql.cj.jdbc.Driver类public class Driver extends NonReGISteringDriver implements java.sql.Driver {    //    // Register ourselves with the DriverManager    //    static {        try {            //调用DriverManager注册自身,DriverManager使用CopyOnWriteArrayList来存储已加载的数据库驱动,然后当创建连接时最终会调用DriverManager的getConnection方法,这才是真正面向数据库的,只不过spring的jdbc帮助我们屏蔽了这些细节            java.sql.DriverManager.registerDriver(new Driver());        } catch (SQLException E) {            throw new RuntimeException("Can't register driver!");        }    }

上面已经来到了DriverManager类,那么DriverManager类里面是否有什么秘密呢,继续往下走,

看下DriverManager的重要方法:

static {        //静态方法,jvm第一次加载该类时会调用该代码块        loadInitialDrivers();        println("JDBC DriverManager initialized");    }     //DriverManager类的loadInitialDrivers方法     private static void loadInitialDrivers() {        String drivers;        try {            drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {                public String run() {                    return System.getProperty("jdbc.drivers");                }            });        } catch (Exception ex) {            drivers = null;        }         AccessController.doPrivileged(new PrivilegedAction<Void>() {            public Void run() {                             //这就是最终的谜底,最终通过ServiceLoader来加载SPI机制提供的驱动,本文用到了两个,一个是mysql的,一个是oracle的,注意该方法只会在jvm第一次加载DriverManager类时才会调用,所以会一次性加载所有的数据库驱动                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);                Iterator<Driver> driversIterator = loadedDrivers.iterator();                                  //下面的代码就是真正完成数据库驱动加载的地方,对应ServiceLoader类的LazyIterator类,所以看下该类的hasNext一级next方法即可,上面已经讲过,这里就不再赘述                try{                    while(driversIterator.hasNext()) {                        driversIterator.next();                    }                } catch(Throwable t) {                // Do nothing                }                return null;            }        });         println("DriverManager.initialize: jdbc.drivers = " + drivers);         if (drivers == null || drivers.equals("")) {            return;        }        String[] driversList = drivers.split(":");        println("number of Drivers:" + driversList.length);        for (String aDriver : driversList) {            try {                println("DriverManager.Initialize: loading " + aDriver);                Class.forName(aDriver, true,                        ClassLoader.getSystemClassLoader());            } catch (Exception ex) {                println("DriverManager.Initialize: load failed: " + ex);            }        }    }

好了,上面已经把springboot如何使用jdk的spi机制来加载数据库驱动的,至于DriverManager的getConnection方法调用过程可以使用类似的方式分析下,在DriverManager的getConnection方法打个断点,当代码停在断点处时,通过idea或者eclipse的堆栈信息就可以看出个大概了。

“如何使用springboot通过spi机制加载mysql驱动”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

您可能感兴趣的文档:

--结束END--

本文标题: 如何使用springboot通过spi机制加载mysql驱动

本文链接: https://www.lsjlt.com/news/299285.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何使用springboot通过spi机制加载mysql驱动
    本篇内容介绍了“如何使用springboot通过spi机制加载mysql驱动”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!SPI是一种JDK...
    99+
    2023-06-20
  • 使用springboot通过spi机制加载mysql驱动的过程
    SPI是一种JDK提供的加载插件的灵活机制,分离了接口与实现,就拿常用的数据库驱动来说,我们只需要在spring系统中引入对应的数据库依赖包(比如mysql-connector-ja...
    99+
    2024-04-02
  • JDBC以反射机制加载类注册驱动连接MySQL
    package test.jdbc; //JDBC注册驱动的另一种方式:(这种方式常用) public class JDBC3 { public static void m...
    99+
    2024-04-02
  • springboot如何通过@PropertySource加载自定义yml文件
    目录@PropertySource加载自定义yml文件@PropertySource注解对于yml的支持@PropertySource加载自定义yml文件 使用@PropertySo...
    99+
    2024-04-02
  • JavaScript如何通过Ajax动态加载CheckBox复选框
    这篇文章将为大家详细讲解有关JavaScript如何通过Ajax动态加载CheckBox复选框,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体代码如下所示:<pr...
    99+
    2024-04-02
  • 如何通过原生vue添加滚动加载更多功能
    这篇文章给大家分享的是有关如何通过原生vue添加滚动加载更多功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。vue中添加滚动加载更多,因为是单页面所以需要在跳出页面时候销毁滚动...
    99+
    2024-04-02
  • mysql如何通过二进制包安装及卸载
    这篇文章主要为大家展示了“mysql如何通过二进制包安装及卸载”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“mysql如何通过二进制包安装及卸载”这篇文章吧。 ...
    99+
    2024-04-02
  • Win11 BitLocker驱动器加密如何使用
    Win11 BitLocker驱动器加密如何使用?相信大家都遇到过自己的电脑问题,那么win11 BitLocker驱动器加密怎么使用呢?其实这个问题不难很多小伙伴不知道怎么详细操作,小编下面整理了Win11 BitLocker驱动器加密使...
    99+
    2023-07-10
  • 利用Java如何实现动态加载数据库驱动
    利用Java如何实现动态加载数据库驱动?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。代码实现在此只例出核心代码,就是动态加载数据库驱动的类,只是此处暂时没有考虑到数据库连接池的...
    99+
    2023-05-31
    java 动态加载 驱动
  • 如何使用Java扩展机制加载所有JAR包
    本篇文章为大家展示了如何使用Java扩展机制加载所有JAR包,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java 扩展机制在Java教程中被描述为一种“通过标准可扩展的方式来让Java平台上所有应...
    99+
    2023-06-17
  • Echarts教程之如何通过Ajax实现动态加载折线图
    这篇文章主要介绍Echarts教程之如何通过Ajax实现动态加载折线图,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、GIF图二、前台代码// 调用方法 hotlineLine(); ...
    99+
    2023-06-08
  • 使用SpringBoot如何实现加载静态资源
    这篇文章给大家介绍使用SpringBoot如何实现加载静态资源,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。在SpringBoot中加载静态资源和在普通的web应用中不太一样。默认情况下,spring Boot从cla...
    99+
    2023-05-31
    springboot 静态资源
  • 如何使用CSS3代码制作页面圆圈加载动画
    这篇文章主要为大家展示了“如何使用CSS3代码制作页面圆圈加载动画”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何使用CSS3代码制作页面圆圈加载动画”这篇文...
    99+
    2024-04-02
  • 如何使用SSH加密MySQL复制
    这篇文章将为大家详细讲解有关如何使用SSH加密MySQL复制,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。其实MySQL很受人欢迎的原因,有它的免费性与开源性,而且MyS...
    99+
    2024-04-02
  • Vue加载中动画组件如何使用
    这篇文章主要介绍“Vue加载中动画组件如何使用”,在日常操作中,相信很多人在Vue加载中动画组件如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue加载中动画组件如何使用”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-29
  • SpringBoot如何使用RateLimiter通过AOP方式进行限流
    目录使用RateLimiter通过AOP方式进行限流1、引入依赖2、自定义注解3、AOP实现类4、使用SpringBoot之限流限流的基础算法Guava RateLimiter其他使...
    99+
    2024-04-02
  • 如何通过php接口和ECharts实现统计图的数据动态加载
    如何通过PHP接口和ECharts实现统计图的数据动态加载【引言】随着数据可视化越来越受到企业和开发者的重视,统计图的应用越来越广泛。ECharts作为一款开源的JavaScript图表库,提供了丰富的图表类型和交互手段,结合PHP接口,可...
    99+
    2023-12-17
    echarts PHP接口 数据动态加载
  • 如何使用纯CSS实现的win8开机加载的动画特效
    这篇文章主要介绍如何使用纯CSS实现的win8开机加载的动画特效,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!实现的代码。html代码:<div class="wra...
    99+
    2024-04-02
  • 如何使用PHP7的命名空间和自动加载机制提高代码的可维护性?
    如何使用PHP7的命名空间和自动加载机制提高代码的可维护性在开发大型的PHP应用程序时,使用命名空间和自动加载机制是非常重要的。这些特性可以提高代码的可维护性,并且使得代码更易于理解和复用。本文将介绍如何使用PHP7的命名空间和自动加载机制...
    99+
    2023-10-22
    PHP 命名空间 自动加载机制
  • AngularJS如何使用angular.bootstrap完成模块手动加载
    这篇文章主要介绍AngularJS如何使用angular.bootstrap完成模块手动加载,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!本文实例分析了AngularJS使用angu...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作