JDBC加载mysql驱动模块

       JDBC加载驱动模块核心类就是DriverManager,例如当我们还不用自动加载服务时,我们过去平常加载mysql的两种方式都必须用到DriverManager类

	①、方式一
        Driver driver = new Driver();//com.mysql.jdbc.Driver
        DriverManager.registerDriver(driver);
    ②、方式二
        Class.forName("com.mysql.jdbc.Driver");
        下面是com.mysql.jdbc.Driver的源码
        public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    
    
            static {
    
    
                try {
    
    
                    java.sql.DriverManager.registerDriver(new Driver());
                } catch (SQLException E) {
    
    
                    throw new RuntimeException("Can't register driver!");
                }
            }
        }

       下面我们开始源码讲解,从DriverManager开始

public class DriverManager {
    
    
    static {
    
    
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
    private static void loadInitialDrivers() {
    
    
        String drivers;
        try {
    
    
        drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
    
    
            public String run() {
    
    
                return System.getProperty("jdbc.drivers");//若jvm有设置系统变量jdbc.drivers=xxxx,那么这里会返回字符串"xxxx"
            }
        });
        } catch (Exception ex) {
    
    
            drivers = null;
        }

        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) {
    
    
                }
            return null;
            }
        });
        println("DriverManager.initialize: jdbc.drivers = " + drivers);
        if (drivers == null || drivers.equals("")) {
    
    
            return;
        }
        String[] driversList = drivers.split(":");//若jvm系统变量jdbc.drivers需要设置多个jdbc驱动模块,则需以“:”分隔开。
        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);
            }
        }
    }
}

       下面是ServiceLoader类,该类的作用就是用于自动加载服务的,该类在使用SPI机制时候是必须用到的核心类,DriverManager类中也使用了该类。

       简单讲解一下调用过程
       DriverManager里调用了ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class); 我们看一下该方法

public static <S> ServiceLoader<S> load(Class<S> service) {
    
    
        ClassLoader cl = Thread.currentThread().getContextClassLoader();//获取到AppClassLoader
        return ServiceLoader.load(service, cl);//这里就会调用到下面的load方法
    }
public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader){
    
    
        return new ServiceLoader<>(service, loader);//new 一个ServiceLoader,以AppClassLoader和Driver作为参数
    }

       由于load方法最终返回的是new ServiceLoader,所以接下来看一下ServiceLoader的构造函数

private ServiceLoader(Class<S> svc, ClassLoader cl) {
    
    
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        reload();//下方的reload方法
    }
public void reload() {
    
    
        providers.clear();//providers是一个LinkedHashMap,用于缓存我们加载的Driver实现类们,所以一开始需要清空,以免数据冲突。
        lookupIterator = new LazyIterator(service, loader);//这个是new一个LazyIterator,将AppClassLoader和Driver作为参数
        //这里的lookupIterator在下面一步会有作用
    }

       接下来轮到Iterator driversIterator = loadedDrivers.iterator();我们看一下该方法。

loadedDrivers.iterator()返回的是一个匿名iterator实现类,但该匿名的实现类的方法里会调用到lookupIterator【是一个LazyIterator】和providers【是一个LinkedHashMap】,代码如下

public Iterator<S> iterator() {
    
    
    return new Iterator<S>() {
    
    
        Iterator<Map.Entry<String,S>> knownProviders = providers.entrySet().iterator();//这里会把缓存providers的iterator赋予knownProviders

                                                                                      //private LinkedHashMap<String,S> providers = new LinkedHashMap<>(); 这里的S现在代表Driver
        public boolean hasNext() {
    
    
            if (knownProviders.hasNext())//这里knownProviders其实就是providers的iterator,所以看一下providers有没有缓存
                return true;
            return lookupIterator.hasNext();//该方法在下方贴出来,走到这里证明缓存providers里还没有Driver的实现类,所以需要去指定的地方加载Deriver实现类,我们通过hasNext方法进而去到hasNextService方法看看,在其方法内解析完所有实现类信息后会返回true。所以这里就得到了true
        }


        public S next() {
    
    
            if (knownProviders.hasNext())
                return knownProviders.next().getValue();
            return lookupIterator.next();
        }


        public void remove() {
    
    
            throw new UnsupportedOperationException();
        }
    };
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面是LazyIterator的方法代码

public boolean hasNext() {
    
    
    if (acc == null) {
    
    
        return hasNextService();
    } else {
    
    
        PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
    
    
            public Boolean run() {
    
     return hasNextService(); }
        };
        return AccessController.doPrivileged(action, acc);
    }
}

private boolean hasNextService() {
    
    
    if (nextName != null) {
    
    
        return true;
    }
    if (configs == null) {
    
    
        try {
    
    
            String fullName = PREFIX + service.getName();//由于PREFIX = "META-INF/services/",service.getName="java.sql.Driver",所以会扫描这个路径文件内的内容
            if (loader == null)
                configs = ClassLoader.getSystemResources(fullName);
            else
                configs = loader.getResources(fullName);//在这里使用了loader也就是Thread.currentThread().getContextClassLoader()所得到的AppClassLoader,configs就得到了所有Driver实现类信息
        } catch (IOException x) {
    
    
            fail(service, "Error locating configuration files", x);
        }
    }
    while ((pending == null) || !pending.hasNext()) {
    
    //初始化的时候pending就是null了————Iterator<String> pending = null;
        if (!configs.hasMoreElements()) {
    
          <------------------------------------------------------------------------------------------------------------
            return false;                                                                                                                                  |
        }                                                                                                                                                  |
        pending = parse(service, configs.nextElement());//在这里开始解析Driver实现类信息,每循环一次处理解析一条信息(也就是一个Driver实现类的全限定名),直到所有信息解析完就return false退出循环。
        //在parse方法里用的是ArrayList<String>来存储我们在META-INF/services/java.sql.Driver文件里配置的所有Driver实现类的全限定名
    }
    nextName = pending.next();//由于上面只是判断pending.hasNext(),所以指标还是没移动,所以指的还是ArrayList<String>里的第一个,所以是有顺序的,而且providers是一个LinkedHashMap,所以在指定文件里写在越前面的越先被执行到。
    return true;
}

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

public S next() {
    
    
    if (acc == null) {
    
    
        return nextService();
    } else {
    
    
        PrivilegedAction<S> action = new PrivilegedAction<S>() {
    
    
            public S run() {
    
     return nextService(); }
        };
        return AccessController.doPrivileged(action, acc);
    }
}

private S nextService() {
    
    
    if (!hasNextService())
        throw new NoSuchElementException();
    String cn = nextName;
    nextName = null;
    Class<?> c = null;
    try {
    
    
        c = Class.forName(cn, false, loader);//加载Driver的实现类,用的loader是当时ServiceLoader构造函数时通过Thread.currentThread().getContextClassLoader()得到的AppClassLoader,这样会打破双亲委任模型
    } catch (ClassNotFoundException x) {
    
    
        fail(service,
             "Provider " + cn + " not found");
    }
    if (!service.isAssignableFrom(c)) {
    
    
        fail(service,
             "Provider " + cn  + " not a subtype");
    }
    try {
    
    
        S p = service.cast(c.newInstance());//实例化Driver的实现类
        providers.put(cn, p);//将实例化的Driver实现类存入providers做缓存。
        return p;
    } catch (Throwable x) {
    
    
        fail(service,
             "Provider " + cn + " could not be instantiated",
             x);
    }
    throw new Error();          // This cannot happen
}

       所以接下来的

while(driversIterator.hasNext()) 
    {
    
    
       driversIterator.next();
     }

       就会用到上面匿名iterator实现类的方法了,而其最终是会调用到LazyIterator的hasNextService方法和nextService方法,所以DriverManager的loadInitialDrivers方法执行完后就代表Driver的所有实现类都已经加载好了并实例化。

       接下来我们看看connection的建立。
       当我们需要获取Driver实现类相对应的connection时,就需要用到DriverManager的getConnection方法,例子如下,代码也如下
       例如:DriverManager.getConnection(“jdbc:mysql://localhost:3306/myysql”,“root”,“password”);

       DriverManager的一个重要属性registeredDrivers

       private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList<>();

public static Connection getConnection(String url,String user, String password) throws SQLException {
    
    

    java.util.Properties info = new java.util.Properties();

    if (user != null) {
    
    
        info.put("user", user);
    }
    if (password != null) {
    
    
        info.put("password", password);
    }

    return (getConnection(url, info, Reflection.getCallerClass()));该方法就在下面
}


-----------------------------------------------------------------------------------------------------------------------------------------------------------
private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {
    
    //不管getConnection传的什么参数,最终调用的都是这个getConnection方法
   
    ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
    synchronized(DriverManager.class) {
    
    
        // synchronize loading of the correct classloader.
        if (callerCL == null) {
    
    
            callerCL = Thread.currentThread().getContextClassLoader();
        }
    }


    if(url == null) {
    
    
        throw new SQLException("The url cannot be null", "08001");
    }


    println("DriverManager.getConnection(\"" + url + "\")");
    SQLException reason = null;


    for(DriverInfo aDriver : registeredDrivers) {
    
    //这里的registeredDrivers是重点,只有将Driver的实现类实例对象存进这个registeredDrivers里,该方法执行才有意义,才不会执行了个寂寞。
        // If the caller does not have permission to load the driver then
        // skip it.
        if(isDriverAllowed(aDriver.driver, callerCL)) {
    
    
            try {
    
    
                println("    trying " + aDriver.driver.getClass().getName());
                Connection con = aDriver.driver.connect(url, info);//这里就是在建立连接了。
                if (con != null) {
    
    
                    // Success!
                    println("getConnection returning " + aDriver.driver.getClass().getName());
                    return (con);
                }
            } catch (SQLException ex) {
    
    
                if (reason == null) {
    
    
                    reason = ex;
                }
            }


        } else {
    
    
            println("    skipping: " + aDriver.getClass().getName());
        }



    }


    // if we got here nobody could connect.
    if (reason != null)    {
    
    
        println("getConnection failed: " + reason);
        throw reason;
    }


    println("getConnection: no suitable driver found for "+ url);
    throw new SQLException("No suitable driver found for "+ url, "08001");
}

       从上面代码里得知需要往registeredDrivers里存入Driver实现类的实例化,然后再执行getConnection才有意义,才能得到连接,所以接下来就回到开头我们说的两种加载mysql的方式了,即使是其他数据库驱动模块也是一样。这也就解释了我们开头说的两种加载方式为什么要这么些的原因了———————————DriverManager.registerDriver(driver);

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 {
    
    
        // This is for compatibility with the original DriverManager
        throw new NullPointerException();
    }

    println("registerDriver: " + driver);

}

       而对于我们ServiceLoader的自动加载服务来说呢,就无需进行上面的DriverManager.registerDriver(driver)了,因为在调用到LazyIterator的nextService方法里就已经对Driver的实现类(也就是mysql实现的Driver—com.mysql.jdbc.Driver)进行加载( c = Class.forName(cn, false, loader))以及实例化(c.newInstance())。而在Driver的实现类里呢已经将DriverManager.registerDriver(new Driver());写在了Static块里,当该类被加载时就会被执行,所以这就叫自动加载服务。

       以下乃ServiceLoader的源代码,贴出来可以参考一下。

public final class ServiceLoader<S>
implements Iterable<S>
{
    
    
    private static final String PREFIX = "META-INF/services/";
    // The class or interface representing the service being loaded
    private final Class<S> service;
    // The class loader used to locate, load, and instantiate providers
    private final ClassLoader loader;
    // The access control context taken when the ServiceLoader is created
    private final AccessControlContext acc;
    // Cached providers, in instantiation order
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
    private LazyIterator lookupIterator;

    public void reload() {
    
    
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }

    private ServiceLoader(Class<S> svc, ClassLoader cl) {
    
    
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        reload();
    }

    private class LazyIterator
    implements Iterator<S>
    {
    
    
        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        Iterator<String> pending = null;
        String nextName = null;

        private LazyIterator(Class<S> service, ClassLoader loader) {
    
    
            this.service = service;
            this.loader = loader;
        }

        private boolean hasNextService() {
    
    
            if (nextName != null) {
    
    
                return true;
            }
            if (configs == null) {
    
    
                try {
    
    
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
    
    
                    fail(service, "Error locating configuration files", x);
                }
    
            }
            while ((pending == null) || !pending.hasNext()) {
    
    
                if (!configs.hasMoreElements()) {
    
    
                    return false;
                }
                pending = parse(service, configs.nextElement());
            }
            nextName = pending.next();
            return true;
        }

        private S nextService() {
    
    
            if (!hasNextService())
                throw new NoSuchElementException();
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
    
    
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
    
    
                fail(service,"Provider " + cn + " not found");
            }
            if (!service.isAssignableFrom(c)) {
    
    
                fail(service,"Provider " + cn + " not a subtype");
            }
            try {
    
    
                S p = service.cast(c.newInstance());
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
    
    
                fail(service,"Provider " + cn + " could not be instantiated",x);
            }
            throw new Error(); // This cannot happen
        }

        public boolean hasNext() {
    
    
            if (acc == null) {
    
    
                return hasNextService();
            } else {
    
    
                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
    
    
                    public Boolean run() {
    
     return hasNextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public S next() {
    
    
            if (acc == null) {
    
    
                return nextService();
            } else {
    
    
                PrivilegedAction<S> action = new PrivilegedAction<S>() {
    
    
                    public S run() {
    
     return nextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public void remove() {
    
    
            throw new UnsupportedOperationException();
        }

    }

    public Iterator<S> iterator() {
    
    
        return new Iterator<S>() {
    
    
            Iterator<Map.Entry<String,S>> knownProviders= providers.entrySet().iterator();
            public boolean hasNext() {
    
    
                if (knownProviders.hasNext())
                    return true;
                return lookupIterator.hasNext();
            }

            public S next() {
    
    
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                return lookupIterator.next();
            }

            public void remove() {
    
    
                throw new UnsupportedOperationException();
            }

        };
    }


    public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader){
    
    
        return new ServiceLoader<>(service, loader);
    }

    public static <S> ServiceLoader<S> load(Class<S> service) {
    
    
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }

    public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
    
    
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        ClassLoader prev = null;
        while (cl != null) {
    
    
            prev = cl;
            cl = cl.getParent();
        }
        return ServiceLoader.load(service, prev);
    }
}







猜你喜欢

转载自blog.csdn.net/gwokgwok137/article/details/113926001