JDBC Driver的加载机制
1.用以下代码取得url里对应的Connection
Connection conn = DriverManager.getConnection(url, user, password);
2.进一步查看源代码,可以发现是通过遍历DriverManager里的 DriverInfo来尝试加载url对应的Connection的。那么问题就是,遍历的这些DriverInfo是哪里来的,它在DriverManager里是一个Vector。遍历代码如下:
if (!initialized) {
initialize();
}
synchronized (DriverManager.class){
// use the readcopy of drivers
drivers = readDrivers;
}
// Walk through the loaded drivers attempting to make a connection.
// Remember the first exception that gets raised so we can reraise it.
SQLException reason = null;
for (int i = 0; i < drivers.size(); i++) {
DriverInfo di = (DriverInfo)drivers.elementAt(i);
// If the caller does not have permission to load the driver then
// skip it.
if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
println(" skipping: " + di);
continue;
}
try {
println(" trying " + di);
Connection result = di.driver.connect(url, info);
if (result != null) {
// Success!
println("getConnection returning " + di);
return (result);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
}
3.上面的 initialize();就是问题的关键。进一步阅读源代码,进入loadInitialDrivers()方法。
private static void loadInitialDrivers() {
String drivers;
try {
drivers = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("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.
DriverService ds = new DriverService();
// Have all the privileges to get all the
// implementation of java.sql.Driver
java.security.AccessController.doPrivileged(ds);
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null) {
return;
}
4.这里的DriverService起到了加载驱动的作用,进入DriverService的定义:
class DriverService implements java.security.PrivilegedAction {
Iterator ps = null;
public DriverService() {};
public Object run() {
ps = Service.providers(java.sql.Driver.class);
try {
while (ps.hasNext()) {
ps.next();
} // end while
} catch(Throwable t) {
// Do nothing
}
return null;
} //end run
}
5.(3)里的 java.security.AccessController.doPrivileged(ds);会调用ds的run方法,也就是DriverService的run方法。run方法里ps = Service.providers(java.sql.Driver.class);这一句,会遍历整个classpath上的jar包,包的META-INF/services里有一个文件名为java.sql.Driver的文件,里面记录了这个包里继承了java.sql.Driver的类的类名,执行ps.next();则会加载对应的类。