java forname 原理_jdbc Class.forName是什么原理?

简单解释一下,以下源代码参考自JDK8和MySQL-Connector-8.0.15。

注册JDBC驱动有三种方式:

第一种:

Class.forName(className);

第二种:

DriverManager.registerDriver(driver);

DriverManager.registerDriver(driver, driverAction);

第三种:

System.setProperty("jdbc.drivers", className);

分别看一下它们的源码。

com.mysql.cj.jdbc.Driver的静态初始化块是这样的:

static {

try {

java.sql.DriverManager.registerDriver(new Driver());

} catch (SQLException E) {

throw new RuntimeException("Can't register driver!");

}

}

可以看到它在被加载的时候实际上调用了java.sql.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 {

if(driver != null) {

registeredDrivers.addIfAbsent(new DriverInfo(driver, da));

} else {

throw new NullPointerException();

}

println("registerDriver: " + driver);

}

其中的registeredDrivers是一个CopyOnWriteArrayList,它的每一项元素都存储了一个Driver实例,它们会在getConnection中被遍历,然后调用driver.connect(url, info)来获取Connection实例。

再看一下DriverManager 的静态初始化块:

static {

loadInitialDrivers();

println("JDBC DriverManager initialized");

}

private static void loadInitialDrivers() {

String drivers;

try {

drivers = AccessController.doPrivileged(new PrivilegedAction() {

public String run() {

return System.getProperty("jdbc.drivers");

}

});

} catch (Exception ex) {

drivers = null;

}

AccessController.doPrivileged( ... );

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);

}

}

}

可以看到,在DriverManager被加载的时候,会调用System.getProperty("jdbc.drivers")然后对其中以':'为间隔的每一个Driver类名为参数,调用Class.forName(className),当我们调用System.setProperty("jdbc.drivers", className)的时候就会影响System.getProperty("jdbc.drivers")的返回结果。

好了,现在注册JDBC驱动的方式与原理基本讲完了。

看一下区别:

第三种方式只能在DriverManager的初始化块中生效,若已经被提前加载,则这次注册是不会发挥作用的。

第二种方式是DriverManager定义的静态方式,调用必然生效,除非发生异常。

第一种方式依赖Driver的具体实现,尽管它本质上还是使用了第二种的静态方法,而第二种的参数是一个Driver的实例,所以静态初始化块中的代码也还是会被执行。所以第二种和第一种这两种注册方式其实没有太大区别。

但是也还是有所区别的:

Class.forName(className)使用了反射,略微影响效率,但是由于以字符串为参数,因此可以将JDBC驱动配置在xml等文件中,而这种注册方法是在java.sql.Driver的javadoc中被提倡的:/**

*

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:

*

* {@code Class.forName("foo.bah.Driver")}

*

*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值