Mybatis IO包源码分析
程序员文章站
2022-03-07 19:06:30
...
ClassLoaderWrapper 类是对 ClassLoader 的包装. 怎么理解了?看下这个方法就知道了.
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}
实例化一个 Class.
Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
for (ClassLoader cl : classLoader) {
if (null != cl) {
try {
Class<?> c = Class.forName(name, true, cl);
if (null != c) {
return c;
}
} catch (ClassNotFoundException e) {
// we'll ignore this until all classloaders fail to locate the class
}
}
}
throw new ClassNotFoundException("Cannot find class: " + name);
}
查找资源.
URL getResourceAsURL(String resource, ClassLoader[] classLoader) {
URL url;
for (ClassLoader cl : classLoader) {
if (null != cl) {
// look for the resource as passed in...
url = cl.getResource(resource);
// ...but some class loaders want this leading "/", so we'll add it
// and try again if we didn't find the resource
if (null == url) {
url = cl.getResource("/" + resource);
}
// "It's always in the last place I look for it!"
// ... because only an idiot would keep looking for it after finding it, so stop looking already.
if (null != url) {
return url;
}
}
}
// didn't find it anywhere.
return null;
}
Resources 是 Mybatis 提供的用于读取资源文件的工具类,我们可以看到它仅仅是对 ClassLoaderWrapper 一层浅浅的封装.
VFS 是虚拟文件系统通用的 API.
VFS 提供了新增用户自定义 VFS 的功能.
看了下 VFS 的实现类,没发现啥重要的东西.
接下来的这个类比较重要. ResolverUtil.
一个测试接口,比如用于判断一个类是否是另一个类的父类,看某个类上是否存在某个注解等.
/**
* A simple interface that specifies how to test classes to determine if they
* are to be included in the results produced by the ResolverUtil.
*/
public interface Test {
/**
* Will be called repeatedly with candidate classes. Must return True if a class
* is to be included in the results, false otherwise.
*/
boolean matches(Class<?> type);
}
判断 parent 是否是 type 的父类.
public static class IsA implements Test {
private Class<?> parent;
/** Constructs an IsA test using the supplied Class as the parent class/interface. */
public IsA(Class<?> parentType) {
this.parent = parentType;
}
/** Returns true if type is assignable to the parent type supplied in the constructor. */
@Override
public boolean matches(Class<?> type) {
return type != null && parent.isAssignableFrom(type);
}
@Override
public String toString() {
return "is assignable to " + parent.getSimpleName();
}
}
判断 type 上是否存在注解 annotation.
public static class AnnotatedWith implements Test {
private Class<? extends Annotation> annotation;
/** Constructs an AnnotatedWith test for the specified annotation type. */
public AnnotatedWith(Class<? extends Annotation> annotation) {
this.annotation = annotation;
}
/** Returns true if the type is annotated with the class provided to the constructor. */
@Override
public boolean matches(Class<?> type) {
return type != null && type.isAnnotationPresent(annotation);
}
@Override
public String toString() {
return "annotated with @" + annotation.getSimpleName();
}
}
在 packageNames 下查找 parent 的实现类. 将查找到的结果放入 matches 集合.
public ResolverUtil<T> findImplementations(Class<?> parent, String... packageNames) {
if (packageNames == null) {
return this;
}
Test test = new IsA(parent);
for (String pkg : packageNames) {
find(test, pkg);
}
return this;
}
在 packageNames 下查找被注解 annotation 修饰的类. 将查找到的结果放入 matches 集合.
public ResolverUtil<T> findAnnotated(Class<? extends Annotation> annotation, String... packageNames) {
if (packageNames == null) {
return this;
}
Test test = new AnnotatedWith(annotation);
for (String pkg : packageNames) {
find(test, pkg);
}
return this;
}
递归查找.
public ResolverUtil<T> find(Test test, String packageName) {
String path = getPackagePath(packageName);
try {
// 这里用到了 VFS,我们还是看下 VFS 的实现吧.
List<String> children = VFS.getInstance().list(path);
for (String child : children) {
if (child.endsWith(".class")) {
addIfMatching(test, child);
}
}
} catch (IOException ioe) {
log.error("Could not read package: " + packageName, ioe);
}
return this;
}
再看下 VFS.
VFS 中定义了两个抽象方法,用于子类实现.
// 从 URL 中搜索和 forPath 匹配的路径.
protected abstract List<String> list(URL url, String forPath) throws IOException;
// 判断此 VFS 是否有效.
public abstract boolean isValid();
VFS 类定义好了获取 VFS 实例的逻辑. 优先使用用户自定义的 VFS,其次是系统实现的.
static VFS createVFS() {
// Try the user implementations first, then the built-ins
List<Class<? extends VFS>> impls = new ArrayList<>();
impls.addAll(USER_IMPLEMENTATIONS);
impls.addAll(Arrays.asList((Class<? extends VFS>[]) IMPLEMENTATIONS));
// Try each implementation class until a valid one is found
VFS vfs = null;
for (int i = 0; vfs == null || !vfs.isValid(); i++) {
Class<? extends VFS> impl = impls.get(i);
try {
vfs = impl.getDeclaredConstructor().newInstance();
if (!vfs.isValid()) {
if (log.isDebugEnabled()) {
log.debug("VFS implementation " + impl.getName() +
" is not valid in this environment.");
}
}
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
log.error("Failed to instantiate " + impl, e);
return null;
}
}
if (log.isDebugEnabled()) {
log.debug("Using VFS adapter " + vfs.getClass().getName());
}
return vfs;
}
关于 DefaultVFS 是读取 Jar 文件. 详细的就不分析了.
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}
实例化一个 Class.
Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
for (ClassLoader cl : classLoader) {
if (null != cl) {
try {
Class<?> c = Class.forName(name, true, cl);
if (null != c) {
return c;
}
} catch (ClassNotFoundException e) {
// we'll ignore this until all classloaders fail to locate the class
}
}
}
throw new ClassNotFoundException("Cannot find class: " + name);
}
查找资源.
URL getResourceAsURL(String resource, ClassLoader[] classLoader) {
URL url;
for (ClassLoader cl : classLoader) {
if (null != cl) {
// look for the resource as passed in...
url = cl.getResource(resource);
// ...but some class loaders want this leading "/", so we'll add it
// and try again if we didn't find the resource
if (null == url) {
url = cl.getResource("/" + resource);
}
// "It's always in the last place I look for it!"
// ... because only an idiot would keep looking for it after finding it, so stop looking already.
if (null != url) {
return url;
}
}
}
// didn't find it anywhere.
return null;
}
Resources 是 Mybatis 提供的用于读取资源文件的工具类,我们可以看到它仅仅是对 ClassLoaderWrapper 一层浅浅的封装.
VFS 是虚拟文件系统通用的 API.
VFS 提供了新增用户自定义 VFS 的功能.
看了下 VFS 的实现类,没发现啥重要的东西.
接下来的这个类比较重要. ResolverUtil.
一个测试接口,比如用于判断一个类是否是另一个类的父类,看某个类上是否存在某个注解等.
/**
* A simple interface that specifies how to test classes to determine if they
* are to be included in the results produced by the ResolverUtil.
*/
public interface Test {
/**
* Will be called repeatedly with candidate classes. Must return True if a class
* is to be included in the results, false otherwise.
*/
boolean matches(Class<?> type);
}
判断 parent 是否是 type 的父类.
public static class IsA implements Test {
private Class<?> parent;
/** Constructs an IsA test using the supplied Class as the parent class/interface. */
public IsA(Class<?> parentType) {
this.parent = parentType;
}
/** Returns true if type is assignable to the parent type supplied in the constructor. */
@Override
public boolean matches(Class<?> type) {
return type != null && parent.isAssignableFrom(type);
}
@Override
public String toString() {
return "is assignable to " + parent.getSimpleName();
}
}
判断 type 上是否存在注解 annotation.
public static class AnnotatedWith implements Test {
private Class<? extends Annotation> annotation;
/** Constructs an AnnotatedWith test for the specified annotation type. */
public AnnotatedWith(Class<? extends Annotation> annotation) {
this.annotation = annotation;
}
/** Returns true if the type is annotated with the class provided to the constructor. */
@Override
public boolean matches(Class<?> type) {
return type != null && type.isAnnotationPresent(annotation);
}
@Override
public String toString() {
return "annotated with @" + annotation.getSimpleName();
}
}
在 packageNames 下查找 parent 的实现类. 将查找到的结果放入 matches 集合.
public ResolverUtil<T> findImplementations(Class<?> parent, String... packageNames) {
if (packageNames == null) {
return this;
}
Test test = new IsA(parent);
for (String pkg : packageNames) {
find(test, pkg);
}
return this;
}
在 packageNames 下查找被注解 annotation 修饰的类. 将查找到的结果放入 matches 集合.
public ResolverUtil<T> findAnnotated(Class<? extends Annotation> annotation, String... packageNames) {
if (packageNames == null) {
return this;
}
Test test = new AnnotatedWith(annotation);
for (String pkg : packageNames) {
find(test, pkg);
}
return this;
}
递归查找.
public ResolverUtil<T> find(Test test, String packageName) {
String path = getPackagePath(packageName);
try {
// 这里用到了 VFS,我们还是看下 VFS 的实现吧.
List<String> children = VFS.getInstance().list(path);
for (String child : children) {
if (child.endsWith(".class")) {
addIfMatching(test, child);
}
}
} catch (IOException ioe) {
log.error("Could not read package: " + packageName, ioe);
}
return this;
}
再看下 VFS.
VFS 中定义了两个抽象方法,用于子类实现.
// 从 URL 中搜索和 forPath 匹配的路径.
protected abstract List<String> list(URL url, String forPath) throws IOException;
// 判断此 VFS 是否有效.
public abstract boolean isValid();
VFS 类定义好了获取 VFS 实例的逻辑. 优先使用用户自定义的 VFS,其次是系统实现的.
static VFS createVFS() {
// Try the user implementations first, then the built-ins
List<Class<? extends VFS>> impls = new ArrayList<>();
impls.addAll(USER_IMPLEMENTATIONS);
impls.addAll(Arrays.asList((Class<? extends VFS>[]) IMPLEMENTATIONS));
// Try each implementation class until a valid one is found
VFS vfs = null;
for (int i = 0; vfs == null || !vfs.isValid(); i++) {
Class<? extends VFS> impl = impls.get(i);
try {
vfs = impl.getDeclaredConstructor().newInstance();
if (!vfs.isValid()) {
if (log.isDebugEnabled()) {
log.debug("VFS implementation " + impl.getName() +
" is not valid in this environment.");
}
}
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
log.error("Failed to instantiate " + impl, e);
return null;
}
}
if (log.isDebugEnabled()) {
log.debug("Using VFS adapter " + vfs.getClass().getName());
}
return vfs;
}
关于 DefaultVFS 是读取 Jar 文件. 详细的就不分析了.
上一篇: MySQL如何基于Explain关键字优化索引功能
下一篇: web第一讲:html与css
推荐阅读
-
Mybatis源码分析——运行原理及流程
-
Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
-
Netty源码分析 (十)----- 拆包器之LineBasedFrameDecoder
-
持久层Mybatis3底层源码分析,原理解析
-
MYBATIS源码深度分析---编译环境搭建
-
java io FilterOutputStream源码分析
-
MyBatis源码分析之——配置解析创建SqlSessionFactory的过程
-
Mybatis源码分析
-
啃下MyBatis源码 - MyBatis核心流程三大阶段之代理阶段(binding模块分析)
-
mybatis的使用及源码分析(一) mybatis介绍以及原生Mybatis项目搭建