今天分析一下DbUtils类。类图如下:
从类图中很容易看出DbUtils类提供了一些静态工具方法,方便JDBC操作。根据方法名可以明显看出方法的作用。
这里值得分析的方法是loadDriver方法。根据驱动类名,使用DbUtils的类加载器加载驱动,并返回加载是否成功标志。
/**
* Loads and registers a database driver class.
* If this succeeds, it returns true, else it returns false.
*
* @param driverClassName of driver to load
* @return boolean <code>true</code> if the driver was found, otherwise <code>false</code>
*/
public static boolean loadDriver(String driverClassName) {
return loadDriver(DbUtils.class.getClassLoader(), driverClassName);
}
它有一个重载方法:
/**
* Loads and registers a database driver class.
* If this succeeds, it returns true, else it returns false.
*
* @param classLoader the class loader used to load the driver class
* @param driverClassName of driver to load
* @return boolean <code>true</code> if the driver was found, otherwise <code>false</code>
* @since 1.4
*/
public static boolean loadDriver(ClassLoader classLoader, String driverClassName) {
try {
Class<?> loadedClass = classLoader.loadClass(driverClassName);
if (!Driver.class.isAssignableFrom(loadedClass)) {
return false;
}
@SuppressWarnings("unchecked") // guarded by previous check
Class<Driver> driverClass = (Class<Driver>) loadedClass;
Constructor<Driver> driverConstructor = driverClass.getConstructor();
// make Constructor accessible if it is private
boolean isConstructorAccessible = driverConstructor.isAccessible();
if (!isConstructorAccessible) {
driverConstructor.setAccessible(true);
}
try {
Driver driver = driverConstructor.newInstance();
registerDriver(new DriverProxy(driver));
} finally {
driverConstructor.setAccessible(isConstructorAccessible);
}
return true;
} catch (RuntimeException e) {
return false;
} catch (Exception e) {
return false;
}
}
这个方法执行过程如下:
用指定的类加载器加载指定驱动类
Class<?> loadedClass = classLoader.loadClass(driverClassName);
判断loadedClass是否实现了java.sql.Driver接口
if (!Driver.class.isAssignableFrom(loadedClass)) {
return false;
}
如果是,获取loadedClass 的构造函数,并设置可以访问,
driverConstructor.setAccessible(true);
获取驱动实例,注册驱动。
Driver driver = driverConstructor.newInstance();
registerDriver(new DriverProxy(driver));
查看Driver接口,可以看到getParentLogger方法是JDBC4.1新增的,
//------------------------- JDBC 4.1 -----------------------------------
/**
* Return the parent Logger of all the Loggers used by this driver. This
* should be the Logger farthest from the root Logger that is
* still an ancestor of all of the Loggers used by this driver. Configuring
* this Logger will affect all of the log messages generated by the driver.
* In the worst case, this may be the root Logger.
*
* @return the parent Logger for this driver
* @throws SQLFeatureNotSupportedException if the driver does not use
* {@code java.util.logging}.
* @since 1.7
*/
public Logger getParentLogger() throws SQLFeatureNotSupportedException;
因此利用DriverProxy解决JDK7与JDK6 Driver接口之间的不兼容问题。
/**
* Java 1.7 method.
*/
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
if (parentLoggerSupported) {
try {
Method method = adapted.getClass().getMethod("getParentLogger", new Class[0]);
return (Logger)method.invoke(adapted, new Object[0]);
} catch (NoSuchMethodException e) {
parentLoggerSupported = false;
throw new SQLFeatureNotSupportedException(e);
} catch (IllegalAccessException e) {
parentLoggerSupported = false;
throw new SQLFeatureNotSupportedException(e);
} catch (InvocationTargetException e) {
parentLoggerSupported = false;
throw new SQLFeatureNotSupportedException(e);
}
}
throw new SQLFeatureNotSupportedException();
}