JDBC的注册会涉及到java spi机制,即Service Provideer Interface,主要应用于厂商自定义组件或插件中;简单说就是java来定义接口规则和方法,厂商实现具体逻辑,每家厂商根据自己产品实现的逻辑肯定不相同,但上层直接使用接口时感觉不到取别。就比如java.sql.Dirver。
java spi的具体约定:厂商在自己被引用的jar包下的META-INF/services目录下创建一个以服务接口命名的文件,然后指向具体实现类。
在装载的时候,ServiceLoader这个类就会扫描对应目录,找到这个实现类
但是无论是Driver还是ServiceLoader都在java核心库rt中,他们可以用启动类加载器进行加载;而根据双亲委派机制,启动类加载器是加载不了实现类的,因为不在rt库中,那么这里就要想别的办法加载了。
还好Launcher这个创建扩展类加载器和系统类加载器的类是在rt中,那么也就是说我们可以用Java.lang.Thread中的方法 getContextClassLoader()和 setContextClassLoader(ClassLoader cl)来获取和设置线程的上下文类加载器。
public Launcher() {
Launcher.ExtClassLoader var1;
try {
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
//此处可以看到初始的线程类加载器就是系统类加载器
Thread.currentThread().setContextClassLoader(this.loader);
String var2 = System.getProperty("java.security.manager");
if (var2 != null) {
SecurityManager var3 = null;
if (!"".equals(var2) && !"default".equals(var2)) {
try {
var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
} catch (IllegalAccessException var5) {
} catch (InstantiationException var6) {
} catch (ClassNotFoundException var7) {
} catch (ClassCastException var8) {
}
} else {
var3 = new SecurityManager();
}
if (var3 == null) {
throw new InternalError("Could not create SecurityManager: " + var2);
}
System.setSecurityManager(var3);
}
}
思路是这样的,那么具体的加载过程如何呢
在JDBC规范中明确要求Drive类必须向DriverManager注册自己,所以是用Class.forName也好,设置System.setProperty也好,都是要过DriverManager。
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
在类初始化执行clinit方法的时候,会执行对应的静态代码块,也可以说这是一个类最先被执行的代码,里面有个loadInitialDrivers方法
private static void loadInitialDrivers() {
String drivers;
//一上来先看看有没有通过System.setProperty配置实现类
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("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.
// ServiceLoader.load() replaces the sun.misc.Providers()
//这里就是另一种用ServiceLoader扫描的方式加载实现类,下面展开说
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
/* Load these drivers, so that they can be instantiated.
* It may be the case that the driver class may not be there
* i.e. there may be a packaged driver with the service class
* as implementation of java.sql.Driver but the actual class
* may be missing. In that case a java.util.ServiceConfigurationError
* will be thrown at runtime by the VM trying to locate
* and load the service.
*
* Adding a try catch block to catch those runtime errors
* if driver not available in classpath but it's
* packaged as service and that service is there in classpath.
*/
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
}
});
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 {
//drivers都扫描到了,然后就挨个加载类呗,这里用的是Class.forName的方式,使用SystemClassLoader,默认是系统类加载器
println("DriverManager.Initialize: loading " + aDriver);
Class.forName(aDriver, true,
ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
上面代码使用ServiceLoader的部分实际上是完整的加载流程,如果这段被执行,说明drivers为空直接return。然后这部分代码展开细说一下。
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
return new ServiceLoader<>(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();
}
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
ServiceLoader里面一顿操作,可以确定的是使用的ClassLoader要么取自线程,要么取自system,反正是系统类及系统类加载器之下的类加载器。然后这里有个reload方法,里面搞了个LazyIterator,两个参数,一个spi接口,一个加载器,要干啥不言而喻。
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();
}
}
很明显LazyIterator是重写了Iterator的hasNext和next方法,然后同样使用Class.forName加载实现类,所以DriverManager里面直接调用next就能加载driver实现类。
SPI: 在Java平台中,通常把核心类rt.jar中提供外部服务、可由应用层自行实现的接口称为SPI。