Know the JDK SPI

SPI stands for Service Provider Interface and can be used to extend frameworks and replacement components. The JDK provides the java.util.ServiceLoader utility class, which helps us find, load, and initialize a service interface based on its conventions when using that service interface.

Most developers may not be familiar with it, but they use it regularly. For example, to obtain the MySQL database connection, the code is as follows:

public class MySQLConnect {

    private final static String url ="jdbc:mysql://localhost:3306/test";

    private final static String username = "root";

    private final static String password = "root";

    public static Connection getConnection(a) throws SQLException {
       // Class.forName("com.mysql.jdbc.Driver");
       return DriverManager.getConnection(url,username,password);
    }

    public static void main(String[] args) throws SQLException { System.out.println(getConnection()); }}Copy the code

The above code will run successfully. Then we will analysis the DriverManager. GetConnection (url, username, password), the process of exploring how to get to the database link Connection?

1, first analyze loadInitialDrivers method, its source is as follows:

private static void loadInitialDrivers(a) {
        
    /** * Get the ServiceLoader instance, loadedDrivers = * new ServiceLoader(Driver.class,Thread.currentThread().getContextClassLoader()) */
    ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
    DriversIterator = new LazyIterator(service, loader) */
    Iterator<Driver> driversIterator = loadedDrivers.iterator();

    / * * * application loader (Thread. The currentThread () getContextClassLoader ()) * load under the classpath meta-inf/services/Java, SQL. The Driver file, * Parse the contents of the java.sql.Driver file to store it in a lazyiterator.pending instance variable. * /
    while(driversIterator.hasNext()) {
        / * * * through reflection instantiate Java, SQL, in the Driver file class (com. Mysql. JDBC Driver, com. Mysql. The fabric. The JDBC. FabricMySQLDriver) * /driversIterator.next(); }}Copy the code

Convention: When the service provider provides an implementation of the service interface (java.sql.Driver), create a file named after the service interface in the META-INF/services/ directory of the JAR package. This file contains the concrete implementation class that implements the service interface. When an external application assembs the module, it can find the implementation class name in the meta-INF /services/ jar file and load the instantiation to complete the module injection.

2. Initialize com.mysql.jdbc.driver

 static {
    try {
        // registeredDrivers stores the Dirver instance
        java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
        throw new RuntimeException("Can't register driver!"); }}Copy the code

3. Get the database connection

for(DriverInfo aDriver : registeredDrivers) {

    if(isDriverAllowed(aDriver.driver, callerCL)) {
        try {
            / / get the Connection
            Connection con = aDriver.driver.connect(url, info);
            if(con ! =null) {
                return(con); }}catch (SQLException ex) {
            if (reason == null) { reason = ex; }}}else {
        println("skipping: "+ aDriver.getClass().getName()); }}Copy the code

JDK SPI simple to use

1. Directory structure

2. Sample code


public interface HelloService {

    String sayHello(a);

}

public class CHelloService implements HelloService {

    @Override
    public String sayHello(a) {
        return "Welcome to C world"; }}public class JavaHelloService implements HelloService {

    @Override
    public String sayHello(a) {
        return "Welcome to Java world"; }}Copy the code

3, com. Codersm. Study. JDK. Spi. The HelloService file content


com.codersm.study.jdk.spi.impl.CHelloService
com.codersm.study.jdk.spi.impl.JavaHelloService

Copy the code

4, test,


@Test
public void testSpi(a) {

    ServiceLoader<HelloService> loaders = ServiceLoader.load(HelloService.class);
    for(HelloService loader : loaders) { System.out.println(loader.sayHello()); }}Copy the code

Welcome message supplement, common exchange. Personal wechat public account seeking attention: