5.3 JDBC类加载机制源码解析(破坏双亲委派机制)

5.3 Java类加载机制

       Java的类加载机制称作双亲委派机制,要明白JDBC为什么破坏双亲委派机制就需要明白双亲委派机制是什么,其工作原理如下,启动类加载器BootStrap只加载rt.jar,也就是jdk提供的相关java部分,扩展类加载器只加载java lib/ext扩展目录下的jar包,而用户类加载器App加载用户编写的代码所在目录(classpath)。

       Java加载类的整个过程是自顶向下的,当上级类加载器发现要加载的东西不属于他的范围,就让下级类加载器去加载,这样依次类推。
5.3 JDBC类加载机制源码解析(破坏双亲委派机制)

5.3.1 JDBC为什么要破坏双亲委派机制

       通过上边便已初见端倪,因为JDBC的DriverManager是由Bootstrap类加载器去加载的,调用的方法也是JDBC的方法,但是真正的驱动JDBC里根本没有,所以在这样的机制下Bootstrap类加载器不会向下委培自然也就加载不到了,所以要让用户程序类加载器来加载真正的驱动就需要打破这种机制。


5.3.2 如何实现打破双亲委派机制

       获取连接需要使用DriverManager的方法,该类在使用的时候会初始化执行loadInitialDrivers()方法来获取真正的驱动。

  1. 使用DriverManager初始化驱动
static {
    loadInitialDrivers();
    println("JDBC DriverManager initialized");
}
  1. 初始化驱动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<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();
                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);
            }
        }
    }

  1. load方法
public static <S> ServiceLoader<S> load(Class<S> service) {
	//获取当前线程的ClassLoader(用户线程则是AppClassLoader)
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    return ServiceLoader.load(service, cl);
}
public static <S> ServiceLoader<S> load(Class<S> service,
                                        ClassLoader loader)
{
    return new ServiceLoader<>(service, loader);
}
  1. 设置classLoader
private ServiceLoader(Class<S> svc, ClassLoader cl) {
    service = Objects.requireNonNull(svc, "Service interface cannot be null");
    //开发者用户线程classLoader
    loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
    acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
    reload();
}

5.3.3 DriverManager中的操作方法实例

       获取数据库连接最后调用了getConnection(url, info, Reflection.getCallerClass()),传入了一个反射获取到的当前调用类,后边会用的这个调用类的classLoader。

@CallerSensitive
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()));
}

       在DriverManager中有一个很重要的方法判断该驱动是否能被加载。

private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
        boolean result = false;
        if(driver != null) {
            Class<?> aClass = null;
            try {
            	//该classLoader能否加载到该类,加载到就返回
                aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
            } catch (Exception ex) {
                result = false;
            }
			//加载到该类再和驱动类比较是否同一个类,是则返回true
             result = ( aClass == driver.getClass() ) ? true : false;
        }

        return result;
    }
上一篇:Mybatis(一)Porxy动态代理和sql解析替换


下一篇:inux下文件权限设置中的数字表示权限,比如777,677等,这个根据什么得来的