JDBC使用SPI
/**
* @author zhangcheng
* @date 2021/8/12
*/
public class T01SPI {
public static void main(String[] args) {
Enumeration<Driver> drivers = DriverManager.getDrivers();
Driver driver;
while (drivers.hasMoreElements()) {
driver = drivers.nextElement();
// sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(driver.getClass() + "==>类加载器: " + driver.getClass().getClassLoader());
}
// BootstrapClassLoader
System.out.println("DriverManager的类加载器:" + DriverManager.class.getClassLoader());
}
}
输出结果如下:
class com.mysql.cj.jdbc.Driver==>类加载器: sun.misc.Launcher$AppClassLoader@18b4aac2
class com.alibaba.druid.proxy.DruidDriver==>类加载器: sun.misc.Launcher$AppClassLoader@18b4aac2
class com.alibaba.druid.mock.MockDriver==>类加载器: sun.misc.Launcher$AppClassLoader@18b4aac2
class org.h2.Driver==>类加载器: sun.misc.Launcher$AppClassLoader@18b4aac2
DriverManager的类加载器:null
DriverManager使用的类加载器为null,即通过Bootstrap ClassLoader加载进来的;
而com.mysql.jdbc.Driver是通过Application ClassLoader加载进来的。
由于双亲委派模型,父加载器是拿不到通过子加载器加载的类的。
首先用户自定义的SPI拓展肯定不能通过Bootstrap ClassLoader加载,因为它又不是系统类.
正常通过Application ClassLoader加载.
这里就引出了一个问题,为什么通过Bootstrap ClassLoader加载进来的DriverManager,可以拿到Application ClassLoader加载进来的com.mysql.jdbc.Driver
?
这个现象,就是破坏了双亲委派模型。
为什么要破坏双亲委派模型
因为DriverManager是通过Bootstrap ClassLoader加载进来的,
而com.mysql.jdbc.Driver是通过classpath的JAR包加载进来的。
要想通过DriverManager获得 Driver 的具体实现,必须破坏双亲委派模型才能拿到。
DriverManager是如何拿到com.mysql.jdbc.Driver类的
通过Thread.currentThread().setContextClassLoader(),
将Application ClassLoader设置为线程上下文加载器。
在DriverManager类里通过Thread.currentThread().getContextClassLoader()
拿到Application ClassLoader进行加载。
DriverManager静态代码块
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
loadInitialDrivers()里
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
java.util.ServiceLoader
/**
* Creates a new service loader for the given service type, using the
* current thread's {@linkplain java.lang.Thread#getContextClassLoader
* context class loader}.
*
* <p> An invocation of this convenience method of the form
*
* <blockquote><pre>
* ServiceLoader.load(<i>service</i>)</pre></blockquote>
*
* is equivalent to
*
* <blockquote><pre>
* ServiceLoader.load(<i>service</i>,
* Thread.currentThread().getContextClassLoader())</pre></blockquote>
*
* @param <S> the class of the service type
*
* @param service
* The interface or abstract class representing the service
*
* @return A new service loader
*/
public static <S> ServiceLoader<S> load(Class<S> service) {
// 线程上下文类加载器是 Launcher$AppClassLoader
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// service: java.sql.Driver
return ServiceLoader.load(service, cl);
}
load:537, ServiceLoader (java.util)
run:586, DriverManager$2 (java.sql)
run:583, DriverManager$2 (java.sql)
doPrivileged:-1, AccessController (java.security)
loadInitialDrivers:583, DriverManager (java.sql)
<clinit>:101, DriverManager (java.sql)
main:13, T01SPI (com.zc.basic.z18spi)
入口: ServiceLoader.load()
默认线程创建时候的上下文类加载器就是 Launcher$AppClassLoader
ServiceLoader.load() 方法里全程用的是 传入的 上下文类加载器.
/**为给定的服务类型创建一个新的服务加载程序,使用
*当前线程的{@linkplain java.lang.Thread#getContextClassLoader
*上下文类装入器}。
*/
public static <S> ServiceLoader<S> load(Class<S> service) {
//1.获取当前线程的类加载
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) {
// 判断入参是否为null
service = Objects.requireNonNull(svc, "Service interface cannot be null");
// 2.加载器如果不存在,获取系统类加载器
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
// 3.获取访问控制器
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
public void reload() {
// 清空缓存
providers.clear();
// 初始化内部类,用于遍历提供者
lookupIterator = new LazyIterator(service, loader);
}
属性
private static final String PREFIX = "META-INF/services/";
// 要加载的类
private final Class<S> service;
// 用于加载实现类的类加载器
private final ClassLoader loader;
// 访问控制器
private final AccessControlContext acc;
// 提供者的缓存
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// 一个内部类,用于遍历实现类
private LazyIterator lookupIterator;
现在我们发现重点就在于LazyIterator这个内部类上.
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 {
// 获取META-INF/services下文件全称
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 Iterator<String> parse(Class<?> service, URL u)
throws ServiceConfigurationError {
InputStream in = null;
BufferedReader r = null;
// 存储配置文件中实现类的全限定名
ArrayList<String> names = new ArrayList<>();
try {
in = u.openStream();
r = new BufferedReader(new InputStreamReader(in, "utf-8"));
int lc = 1;
// 读取文件内容
while ((lc = parseLine(service, u, r, lc, names)) >= 0);
} catch (IOException x) {
fail(service, "Error reading configuration file", x);
} finally {
try {
if (r != null) r.close();
if (in != null) in.close();
} catch (IOException y) {
fail(service, "Error closing configuration file", y);
}
}
return names.iterator();
}
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
}