简书 许乐
转载请注明原创出处,谢谢!
一、ClassLoaderWrapper 类
在MyBatis的IO包中封装了ClassLoader以及读取资源文件相关的API。 ClassLoaderWrapper是一个ClassLoader的包装器
,其中包含了多个ClassLoader对象。使用ClassLoaderWrapper就如同使用一个ClassLoader对象,ClassLoaderWrapper 会按照指定的顺序依次检测其中封装的ClassLoader对象,并从中选取第一个可用的ClassLoader完成相关功能。
ClassLoaderWrapper中定义了两个字段,分别记录了系统指定的默认加载器(defaultClassLoader)和系统加载器(systemClassLoader)
ClassLoader defaultClassLoader;//应用指定的默认类加载器
ClassLoader systemClassLoader;// 系统类加载器
【特别注意】defaultClassLoader 和 systemClassLoader的修饰符为包内可见,它们的初始化可以在其它的类中完成。defaultClassLoader会在同一包下的Resources
类中初始化。
ClassLoaderWrapper的主要功能分为三类:
getResourceAsURL()
getResourceAsStream()
-
classForName()
这三个方法逻辑很相似,这里以classForName()
为例进行介绍
public Class classForName(String name) throws ClassNotFoundException {
return classForName(name, getClassLoaders(null));
}
public Class classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
return classForName(name, getClassLoaders(classLoader));
}
真正被调用的方法如下:
private Class classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
for (ClassLoader cl : classLoader) {//遍历所有加载器
if (null != cl) {
try {
Class c = Class.forName(name, true, cl);//使用Class.forName加载一个类
if (null != c) {//直到加载到Class返回
return c;
}
} catch (ClassNotFoundException ignore) {
//ignore
}
}
}
//所有类加载器都加载不到,抛出ClassNotFoundException
throw new ClassNotFoundException("Cannot find class: " + name);
}
getClassLoaders(classLoader)
:
// 返回ClassLoader[] 数组,该数组指明了类加载器的使用顺序
private ClassLoader[] getClassLoaders(ClassLoader classLoader) {
ClassLoader[] classLoaders=new ClassLoader[]{
classLoader,//由参数指定的默认类加载器
defaultClassLoader,//系统指定的默认类加载器
Thread.currentThread().getContextClassLoader(),//当前线程绑定的类加载器
getClass().getClassLoader(),//加载当前类所使用的类加载器
systemClassLoader};//系统类加载器
return classLoaders;
}
二、Resources 类
Resources
类是提供了多个静态方法的工具类,其中封装了一个ClassLoaderWrapper类型的静态字段,Resources 提供的静态方法都是通过调用ClassLoaderWrapper的方法实现,代码比较简单,仅贴出核心代码。
public class Resources {
private static ClassLoaderWrapper classLoaderWrapper =
new ClassLoaderWrapper();
......
}
三、思考与总结:
1. 为什么使用ClassLoaderWrapper而不是JDK提供的ClassLoader?
框架中加载资源的场景非常普遍,有类加载,文件加载(如配置文件,db.properties)等,这些操作普遍需要判断文件、路径、加载器是否为空,还要抛出异常,将这些判断是否为空的逻辑与异常的处理封装起来,简化上层调用逻辑,使得上层代码的结构更清晰。其实这种包装在框架中会普遍存在,因为JDK API只是提供了功能的实现,并没有考虑业务场景的多样性。
感觉就是几乎每一个框架在真正功能实现层(基础层),和外部系统使用层(接口层),之间会多出来一个层(核心层),这一层扮演的角色就是委托,如果有一些逻辑处理,就进行逻辑处理,再调用基础层;没有逻辑处理的就直接调用基础层,而不是直接在对外部系统使用的接口层,来直接耦合基础层的类。这样虽然有些麻烦,但是感觉提高了扩展性,基础层我只提供不变的逻辑处理,而多出来的核心层,可以预处理一些接口层传递过来的数据,核心层处理变化的逻辑。这样就起到复用基础层的提供的功能。
这里也引发了对于SOA服务的思考,或许我们也可以这样去设定,对外暴露的接口,就是这里的核心层,而抽离出来一些不变的逻辑放在基础层,以后有了新的变动,只需要在核心层加接口,实现一些逻辑,复用基础层提供的服务;而不是只有单独一层,每次新变动都需要写新逻辑以及重复copy不变的逻辑。
2. ClassLoaderWrapper 怎么打破了双亲委托模型?
遍历classLoader[]数组,如果加载到所需要的类则返回,类加载器的使用顺序是从数组的第一个元素到最后一个元素。
网友评论