在没有 Class.forName() 或系统属性的情况下如何加载 JDBC 驱动程序? [复制]

Posted

技术标签:

【中文标题】在没有 Class.forName() 或系统属性的情况下如何加载 JDBC 驱动程序? [复制]【英文标题】:How are JDBC drivers loaded without Class.forName() or System Properties? [duplicate] 【发布时间】:2019-01-10 04:10:52 【问题描述】:

我正在尝试了解 JDBC 内部结构,具体来说,我的 JDBC 驱动程序是如何加载的,如果 1. 我没有使用 Class.forName() 2. 检查 jdbc.driver 系统属性返回 null。

我已尝试检查我的类路径并将系统属性的完整列表打印到控制台以按照https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html#registerDriver-java.sql.Driver- 和https://db.apache.org/derby/docs/10.4/devguide/cdevdvlp40653.html 进行检查

下面是 DBConnection 类的 DBConnection 构造函数

    `public DBConnection() 
        try 
            this.conn = DriverManager.getConnection(JDBC_URL);
            if (this.conn != null) 
                System.out.println("Connection successful");
            
         catch(SQLException sqlex) 
            System.out.println("Connection failed");
        
    `
下面是 main()

    public static void main(String[] args) 

        DBConnection dbTest = new DBConnection();

        String sysPropsString = System.getProperties().toString();
        String[] propsArr = sysPropsString.split(",");

        for(String property : propsArr) 
            if (property.contains("class") && property.contains("path") 
                    && (property.contains("derby") || property.contains("drivers")))
                System.out.println(property);
        
        System.out.println("***********************************");
        String sysDrivers = System.getProperty("jdbc.drivers");
        System.out.println(sysDrivers);
    


我希望通过 System.getProperty() 调用将 derby jdbc 驱动程序打印到控制台,或者在类路径中的某个位置找到它,但我没有看到。 derby 驱动是如何加载的?

下面是输出:

连接成功

java.class.path=/Users/aslotu/eclipse-workspace/Bullhorn/build/classes:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_cs.jar: /Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_de_DE.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_es。 jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_fr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/ derbyLocale_hu.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_it.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/ lib/derbyLocale_ja_JP.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_ko_KR.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/ db/lib/derbyLocale_pl.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_pt_BR.jar:/Lib rary/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_ru.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_zh_CN.jar :/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_zh_TW.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derby .jar


【问题讨论】:

从 Java 6 (JDBC 4) 开始,您不需要 Class.forName 来加载 JDBC 驱动程序。相反,如JDBC 4.0 and 4.1 features summary 中所述,自动加载 JDBC 驱动程序。 在早期版本的 JDBC 中,应用程序必须在请求连接之前手动注册驱动程序。使用 JDBC 4.0,应用程序不再需要在驱动程序名称上发出 Class.forName();相反,当应用程序请求连接时,DriverManager 会找到合适的 JDBC 驱动程序。 我不确定是否需要 Class.forName() 用于较新版本的 Java。但是对于您的问题:建议:尝试加载驱动程序,然后 ClassLoader.getSystemClassLoader();,并打印出来自 URL[] urls = ((URLClassLoader)cl).getURLs() 的所有 URL 另见Technotes - JAR File Specification - Service Provider。 当您打印出java.class.path 时,它以“...:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derby.jar”结尾。在我看来,这就像 Derby JDBC 驱动程序。您是否在问您的应用程序如何知道 使用该 .jar 文件? 在 Java 6 中是否需要 Class.forName 取决于驱动程序是否使用正确的类名声明 /META-INF/services/java.sql.Driver,以及驱动程序 jar 是否位于初始类路径或不是。自动加载驱动程序不适用于上下文类路径上的驱动程序(一个常见的例子是放置在 WAR 的WEB-INF/lib 中的驱动程序;那些不会自动加载)。 【参考方案1】:

derby.jar 包含文件META-INF/services/java.sql.Driver 注册org.apache.derby.jdbc.AutoloadedDriver

这项工作是因为 DriverManager 使用 ServiceLoader

【讨论】:

这不是一个真正的答案,因为它高度特定于特定的驱动程序实现。 @jwenting 问题不是针对具体实现的吗? 不像我读的那样。他以德比为例,但在问题本身的文本中没有提到它。 @jwenting 我回答了问题是如何被问到的:“德比驱动程序是如何加载的?” @jwenting 它实际上对所有 JDBC 驱动程序都一样,唯一的区别是 META-INF/services/java.sql.Driver 中的确切类名。

以上是关于在没有 Class.forName() 或系统属性的情况下如何加载 JDBC 驱动程序? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

ClassLoader.loadClass和Class.forName的区别

ClassLoader.loadClass和Class.forName的区别

Class.forName()的作用与使用总结

Class.forName(Class) 在特定目录中?

有没有用 Class.forName() 加载类的替代方法?

Class.forName("com.mysql.jdbc.Driver") 没有在 jar 文件中查找该类