public class DriverManager { .....略.... /** * Load the initial JDBC drivers by checking the System property * jdbc.properties and then use the {@code ServiceLoader} mechanism */ static { 调用loadInitialDrivers方法,继续往里跟进。 loadInitialDrivers(); println("JDBC DriverManager initialized"); } .....略....
private static void loadInitialDrivers() { String drivers; try { //寻找系统属性jdbc.drivers有没有值,jdbc.drivers是加载jdbc驱动的另一种方式,了解即可 drivers = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("jdbc.drivers"); } }); } catch (Exception ex) { drivers = null; } // If the driver is packaged as a Service Provider, load it. // Get all the drivers through the classloader // exposed as a java.sql.Driver.class service. // ServiceLoader.load() replaces the sun.misc.Providers()
/* Load these drivers, so that they can be instantiated. * It may be the case that the driver class may not be there * i.e. there may be a packaged driver with the service class * as implementation of java.sql.Driver but the actual class * may be missing. In that case a java.util.ServiceConfigurationError * will be thrown at runtime by the VM trying to locate * and load the service. * * Adding a try catch block to catch those runtime errors * if driver not available in classpath but it's * packaged as service and that service is there in classpath. */ try{ while(driversIterator.hasNext()) { driversIterator.next(); } } catch(Throwable t) { // Do nothing } return null; } });
/* 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(); }
private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException { /* * When callerCl is null, we should check the application's * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */ //如果调用者的类加载器不是null,就用调用者的类加载器加载驱动的实现,否则使用当前线程的上下文类加载器, //我们的程序得到的callerCL是系统类加载器。因此synchronized里边的if不会进入执行。 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"); }
// Walk through the loaded registeredDrivers attempting to make a connection. // Remember the first exception that gets raised so we can reraise it. SQLException reason = null; //registeredDrivers是我们刚刚分析的,将当前classPath下的com.sql.Driver实现类的集合,当前的程序有2个mysql的驱动实现类。 for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. //这个方法很重要,我们进去看一下,即callerCL带进去,即将系统类加载器带进去 if(isDriverAllowed(aDriver.driver, callerCL)) { try { println(" trying " + aDriver.driver.getClass().getName()); Connection con = aDriver.driver.connect(url, info); //如果某一个连接返回的不是null,证明这个驱动就是我们要的驱动,就可以返回了。 if (con != null) { // Success! println("getConnection returning " + aDriver.driver.getClass().getName()); return (con); } } catch (SQLException ex) { if (reason == null) { reason = ex; } }