【Mybatis】【基础设施】【三】Mybatis源码解析-VFS虚拟文件系统
1 前言
这节我们介绍Mybatis又一个出现的基础设施VFS,他是干啥的呢,就是加载指定目录下的文件的。
前置知识:java.net.URL这个类知道么,不要看名字把它觉得就是我们浏览器里的URL,它不是奥。它叫统一资源定位符有:http、https、file和jar。
2 源码分析
看源码前我们简单看一下类图:
VFS是个抽象类,下边有两个子类DefaultVFS、JBOss6VFS,有点模板模式的意思奥。 两个抽象方法是:
/** * Return true if the {@link VFS} implementation is valid for the current environment. * 当前的VFS是否可用 * @return true, if is valid */ public abstract boolean isValid(); /** * Recursively list the full resource path of all the resources that are children of the * resource identified by a URL. * 列出某个URL下的资源 forPath下的 * @param url The URL that identifies the resource to list. * @param forPath The path to the resource that is identified by the URL. Generally, this is the * value passed to {@link #getResources(String)} to get the resource URL. * @return A list containing the names of the child resources. * @throws IOException If I/O errors occur */ protected abstract List<String> list(URL url, String forPath) throws IOException;
好了,那我们具体看下VFS的源码:
public abstract class VFS { private static final Log log = LogFactory.getLog(VFS.class); // 两个子类 public static final Class<?>[] IMPLEMENTATIONS = { JBoss6VFS.class, DefaultVFS.class }; // 用户自定义实现 public static final List<Class<? extends VFS>> USER_IMPLEMENTATIONS = new ArrayList<>(); /** Singleton instance holder. */ // 单例的对象实例化拥有者,也就是要想获得VFS实例,就直接VFSHolder.INSTANCE即可。 private static class VFSHolder { static final VFS INSTANCE = createVFS(); @SuppressWarnings("unchecked") // 实例化VFS static VFS createVFS() { //合并用户自定义实现和默认的两个实现 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() && 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; } } /** * Get the singleton {@link VFS} instance. If no {@link VFS} implementation can be found for the current environment, * then this method returns null. * 获取VFS实例 * @return single instance of VFS */ public static VFS getInstance() { return VFSHolder.INSTANCE; } // 添加自定义实现 public static void addImplClass(Class<? extends VFS> clazz) { if (clazz != null) { USER_IMPLEMENTATIONS.add(clazz); } } // 加载指定全类名的类 protected static Class<?> getClass(String className) { try { return Thread.currentThread().getContextClassLoader().loadClass(className); // return ReflectUtil.findClass(className); } catch (ClassNotFoundException e) { if (log.isDebugEnabled()) { log.debug("Class not found: " + className); } return null; } } // 获取某个类的方法 protected static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) { if (clazz == null) { return null; } try { return clazz.getMethod(methodName, parameterTypes); } catch (SecurityException e) { log.error("Security exception looking for method " + clazz.getName() + "." + methodName + ". Cause: " + e); return null; } catch (NoSuchMethodException e) { log.error("Method not found " + clazz.getName() + "." + methodName + "." + methodName + ". Cause: " + e); return null; } } // 执行某个类的方法 protected static <T> T invoke(Method method, Object object, Object... parameters) throws IOException, RuntimeException { try { return (T) method.invoke(object, parameters); } catch (IllegalArgumentException | IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof IOException) { throw (IOException) e.getTargetException(); } else { throw new RuntimeException(e); } } } // 获取某个路径下的资源 protected static List<URL> getResources(String path) throws IOException { return Collections.list(Thread.currentThread().getContextClassLoader().getResources(path)); } public abstract boolean isValid(); protected abstract List<String> list(URL url, String forPath) throws IOException; // 获取路径下的文件 public List<String> list(String path) throws IOException { List<String> names = new ArrayList<>(); for (URL url : getResources(path)) { names.addAll(list(url, path)); } return names; } public static void main(String[] args) throws IOException { VFS instance = VFS.getInstance(); List<String> list = instance.list("org/apache/ibatis/type"); System.out.println(list); } }
总结一下的大概的方法有:
- 有一个静态内部类VFSHolder,用于初始化VFS对象,并持有其单例
- addImplClass 添加自定义实现
- getClass 根据全类名加载某个类
- getInstance 获取VFS实例
- getMethod 获取某个类的某个方法
- getResources 获取某个路径下的资源列表 通过类加载器
- invoke 执行某个方法
- isValid 当前VFS是否可用
- list(path) 获取某个路径下的所有文件名
- list(URL url, String forPath) 获取某个路径下指定的子路径下的所有文件名
3 示例
4 小结
好了,关于VFS的介绍就到这里了,知道它是用来加载某个路径下的资源即可,有理解不对的地方欢迎指正哈。