SPI在数据库驱动中的应用

196 阅读1分钟

SPI在数据库驱动中的应用

# Java SPI机制详解

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.29</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>42.3.3</version>
</dependency>

image.png

image.png

package org.example;
import java.sql.Driver;
import java.sql.DriverManager;

public class App 
{
    private final static Logger logger = LoggerFactory.getLogger(App.class);
    public static void main( String[] args ) throws IOException, ClassNotFoundException {
        Class.forName("java.sql.DriverManager");
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            logger.info("{}", driver.getClass().getName());
        }
    }
}

image.png

Java提供的驱动管理器,DriverManager

package java.sql;
public class DriverManager {
    // List of registered JDBC drivers
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
  
    private DriverManager(){}

    /**
     * Load the initial JDBC drivers by checking the System property
     * jdbc.properties and then use the {@code ServiceLoader} mechanism
     */
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
    private static void loadInitialDrivers() {
        String drivers;
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });
    }
    
    public static synchronized void registerDriver(java.sql.Driver driver)
        throws SQLException {
        registerDriver(driver, null);
    }
    
    public static synchronized void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {
        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            throw new NullPointerException();
        }
        println("registerDriver: " + driver);
    }
}

DriverManager类加载的时候执行loadInitialDrivers()通过ServiceLoader.load(Driver.class)获取所有第三方库实现的Driver;虽然只是遍历一遍所有的Driver实例但是类加载器会加载这些类到jvm届时将执行Driver实现类的静态代码块把自己注册到DriverManager即添加到DriverManager的registeredDrivers容器中。

mysql实现的Driver

package com.mysql.cj.jdbc;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    /**
     * Construct a new driver and register it with DriverManager
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

postgresql实现的Driver

package org.postgresql;
public class Driver implements java.sql.Driver {
    private static @Nullable Driver registeredDriver;
    
    static {
        try {
            register();
        } catch (SQLException var1) {
            throw new ExceptionInInitializerError(var1);
        }
    }
    
    public static void register() throws SQLException {
        if (isRegistered()) {
            throw new IllegalStateException("Driver is already registered. It can only be registered once.");
        } else {
            Driver registeredDriver = new Driver();
            DriverManager.registerDriver(registeredDriver);
            Driver.registeredDriver = registeredDriver;
        }
    }
}