JDBC 是如何破坏双亲委派机制的?

发布于 2022-09-11 20:55:46 字数 810 浏览 44 评论 0

我看了好多的博客,但是说的都很笼统。但是大致意思如下,
DriverManager 这个类 存在在 rt.jar里面由启动类加载器加载,而它里面需要用到外部引入的jar,比如说 mysql-connect.jar里面的Driver,于是DriverManager这个类不得不使用 Thread ContextClassLoader 去加载外部的具体实现.
(由这个星号标识的部分是我非常不理解的)
我仔细也试着去读代码,发现跟他们说的不一致.
我的疑问如下:
1.
Class.forName("com.mysql...");
这句话加载驱动,使用了那种类型的加载器,据我的理解应该是应用类加载器. 对吗?
2.
在mysql的Driver实现类中,使用static静态代码块,调用了DriverManager.registerDriver(new Driver()).
然后DriverManager中就持有了这个Driver,并没有发现.DriverManager 通过 ContextClassLoader去加载这个Driver的代码.
虽然DriverManager.getConnection()方法里面由一段这样的代码

synchronized(DriverManager.class) {

if (callerCL == null) {
    callerCL = Thread.currentThread().getContextClassLoader();
}

}

但是它用的driver还是register的driver,并不是由callerCL加载的.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浮世清欢 2022-09-18 20:55:46

上面使用Class.forName的方式注册驱动是比较古老的方式拉,新的DriverManager中会通过SPI机制自动加载驱动,只要classpath中有相应的驱动包即可。
在新的版本中,不需要显式的加载驱动,直接DriverManager.getConnection即可。
新的DriverManager加载驱动的过程是在loadInitialDrivers方法中进行的。

    //加载驱动类有两种方式,
    //1种是通过jdbc.drivers设置驱动类的位置,然后通过SystemClassLoader
    //另外一种通过spi机制加载
    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() {
                //在这里会通过Thread.currentThread().getContextClassLoader()加载
                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);
                //这里是通过SystemLoader加载
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
                println("DriverManager.Initialize: load failed: " + ex);
            }
        }
    }

上面的方法知识加载驱动类,具体的注册逻辑在Driver类中,可查看Driver接口的说明:

/**
 * <P>When a Driver class is loaded, it should create an instance of
 * itself and register it with the DriverManager. This means that a
 * user can load and register a driver by calling:
 * <p>
 * {@code Class.forName("foo.bah.Driver")}
 * <p>
 **/
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文