JDBC加载驱动模块核心类就是DriverManager,例如当我们还不用自动加载服务时,我们过去平常加载mysql的两种方式都必须用到DriverManager类
①、方式一
Driver driver = new Driver();//com.mysql.jdbc.Driver
DriverManager.registerDriver(driver);
②、方式二
Class.forName("com.mysql.jdbc.Driver");
下面是com.mysql.jdbc.Driver的源码
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
下面我们开始源码讲解,从DriverManager开始
public class DriverManager {
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");//若jvm有设置系统变量jdbc.drivers=xxxx,那么这里会返回字符串"xxxx"
}
});
} catch (Exception ex) {
drivers = null;
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
}
return null;
}
});
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");//若jvm系统变量jdbc.drivers需要设置多个jdbc驱动模块,则需以“:”分隔开。
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);
}
}
}
}
下面是ServiceLoader类,该类的作用就是用于自动加载服务的,该类在使用SPI机制时候是必须用到的核心类,DriverManager类中也使用了该类。
简单讲解一下调用过程
DriverManager里调用了ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class); 我们看一下该方法
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();//获取到AppClassLoader
return ServiceLoader.load(service, cl);//这里就会调用到下面的load方法
}
public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader){
return new ServiceLoader<>(service, loader);//new 一个ServiceLoader,以AppClassLoader和Driver作为参数
}
由于load方法最终返回的是new ServiceLoader,所以接下来看一下ServiceLoader的构造函数
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();//下方的reload方法
}
public void reload() {
providers.clear();//providers是一个LinkedHashMap,用于缓存我们加载的Driver实现类们,所以一开始需要清空,以免数据冲突。
lookupIterator = new LazyIterator(service, loader);//这个是new一个LazyIterator,将AppClassLoader和Driver作为参数
//这里的lookupIterator在下面一步会有作用
}
接下来轮到Iterator driversIterator = loadedDrivers.iterator();我们看一下该方法。
loadedDrivers.iterator()返回的是一个匿名iterator实现类,但该匿名的实现类的方法里会调用到lookupIterator【是一个LazyIterator】和providers【是一个LinkedHashMap】,代码如下
public Iterator<S> iterator() {
return new Iterator<S>() {
Iterator<Map.Entry<String,S>> knownProviders = providers.entrySet().iterator();//这里会把缓存providers的iterator赋予knownProviders
//private LinkedHashMap<String,S> providers = new LinkedHashMap<>(); 这里的S现在代表Driver
public boolean hasNext() {
if (knownProviders.hasNext())//这里knownProviders其实就是providers的iterator,所以看一下providers有没有缓存
return true;
return lookupIterator.hasNext();//该方法在下方贴出来,走到这里证明缓存providers里还没有Driver的实现类,所以需要去指定的地方加载Deriver实现类,我们通过hasNext方法进而去到hasNextService方法看看,在其方法内解析完所有实现类信息后会返回true。所以这里就得到了true
}
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面是LazyIterator的方法代码
public boolean hasNext() {
if (acc == null) {
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() {
return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();//由于PREFIX = "META-INF/services/",service.getName="java.sql.Driver",所以会扫描这个路径文件内的内容
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);//在这里使用了loader也就是Thread.currentThread().getContextClassLoader()所得到的AppClassLoader,configs就得到了所有Driver实现类信息
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
//初始化的时候pending就是null了————Iterator<String> pending = null;
if (!configs.hasMoreElements()) {
<------------------------------------------------------------------------------------------------------------
return false; |
} |
pending = parse(service, configs.nextElement());//在这里开始解析Driver实现类信息,每循环一次处理解析一条信息(也就是一个Driver实现类的全限定名),直到所有信息解析完就return false退出循环。
//在parse方法里用的是ArrayList<String>来存储我们在META-INF/services/java.sql.Driver文件里配置的所有Driver实现类的全限定名
}
nextName = pending.next();//由于上面只是判断pending.hasNext(),所以指标还是没移动,所以指的还是ArrayList<String>里的第一个,所以是有顺序的,而且providers是一个LinkedHashMap,所以在指定文件里写在越前面的越先被执行到。
return true;
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
public S next() {
if (acc == null) {
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() {
return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);//加载Driver的实现类,用的loader是当时ServiceLoader构造函数时通过Thread.currentThread().getContextClassLoader()得到的AppClassLoader,这样会打破双亲委任模型
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service,
"Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());//实例化Driver的实现类
providers.put(cn, p);//将实例化的Driver实现类存入providers做缓存。
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
}
所以接下来的
while(driversIterator.hasNext())
{
driversIterator.next();
}
就会用到上面匿名iterator实现类的方法了,而其最终是会调用到LazyIterator的hasNextService方法和nextService方法,所以DriverManager的loadInitialDrivers方法执行完后就代表Driver的所有实现类都已经加载好了并实例化。
接下来我们看看connection的建立。
当我们需要获取Driver实现类相对应的connection时,就需要用到DriverManager的getConnection方法,例子如下,代码也如下
例如:DriverManager.getConnection(“jdbc:mysql://localhost:3306/myysql”,“root”,“password”);
DriverManager的一个重要属性registeredDrivers
private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList<>();
public static Connection getConnection(String url,String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
if (user != null) {
info.put("user", user);
}
if (password != null) {
info.put("password", password);
}
return (getConnection(url, info, Reflection.getCallerClass()));该方法就在下面
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------
private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {
//不管getConnection传的什么参数,最终调用的都是这个getConnection方法
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
SQLException reason = null;
for(DriverInfo aDriver : registeredDrivers) {
//这里的registeredDrivers是重点,只有将Driver的实现类实例对象存进这个registeredDrivers里,该方法执行才有意义,才不会执行了个寂寞。
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);//这里就是在建立连接了。
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
// if we got here nobody could connect.
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
throw new SQLException("No suitable driver found for "+ url, "08001");
}
从上面代码里得知需要往registeredDrivers里存入Driver实现类的实例化,然后再执行getConnection才有意义,才能得到连接,所以接下来就回到开头我们说的两种加载mysql的方式了,即使是其他数据库驱动模块也是一样。这也就解释了我们开头说的两种加载方式为什么要这么些的原因了———————————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 {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
而对于我们ServiceLoader的自动加载服务来说呢,就无需进行上面的DriverManager.registerDriver(driver)了,因为在调用到LazyIterator的nextService方法里就已经对Driver的实现类(也就是mysql实现的Driver—com.mysql.jdbc.Driver)进行加载( c = Class.forName(cn, false, loader))以及实例化(c.newInstance())。而在Driver的实现类里呢已经将DriverManager.registerDriver(new Driver());写在了Static块里,当该类被加载时就会被执行,所以这就叫自动加载服务。
以下乃ServiceLoader的源代码,贴出来可以参考一下。
public final class ServiceLoader<S>
implements Iterable<S>
{
private static final String PREFIX = "META-INF/services/";
// The class or interface representing the service being loaded
private final Class<S> service;
// The class loader used to locate, load, and instantiate providers
private final ClassLoader loader;
// The access control context taken when the ServiceLoader is created
private final AccessControlContext acc;
// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
private LazyIterator lookupIterator;
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
private class LazyIterator
implements Iterator<S>
{
Class<S> service;
ClassLoader loader;
Enumeration<URL> configs = null;
Iterator<String> pending = null;
String nextName = null;
private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service,"Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,"Provider " + cn + " could not be instantiated",x);
}
throw new Error(); // This cannot happen
}
public boolean hasNext() {
if (acc == null) {
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() {
return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
public S next() {
if (acc == null) {
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() {
return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public Iterator<S> iterator() {
return new Iterator<S>() {
Iterator<Map.Entry<String,S>> knownProviders= providers.entrySet().iterator();
public boolean hasNext() {
if (knownProviders.hasNext())
return true;
return lookupIterator.hasNext();
}
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader){
return new ServiceLoader<>(service, loader);
}
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
ClassLoader prev = null;
while (cl != null) {
prev = cl;
cl = cl.getParent();
}
return ServiceLoader.load(service, prev);
}
}