Question:
. io包 提供了 哪些 工具类?
. 工具类的实现?
1. ClassLoaderWrapper
提供 根据 Resource 来 获取 相应的 URL , InputStream,
提供 根据 class 名称 获取 相应的 class
其最为重要的方法无非是对 各种 classloader进行了一个包装,如下:
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}
这样,在 相应的 方法里,包括 getResourceAsURL , classForName, getResourceAsStream, 都是对 这个 classLoader 数组进行遍历, 如果 遍历下的 classloader 不为空,则用这个 classloader 来加载 相应的 url, class, inputstream
2. Resources
对 ClassLoaderWrapper 进行了包装, 提供给外部接口调用
3. VFS
Provides a very simple API for accessing resources within an application server.提供简单的api 从相应服务器获取resource, 其实现类包括DefaultVFS 和 JBoss6VFS,提供的api为:
/**
* Recursively list the full resource path of all the resources that are children of all the
* resources found at the specified path.
*
* @param path The path of the resource(s) to list.
* @return A list containing the names of the child resources.
* @throws IOException If I/O errors occur
*/
public List<String> list(String path) throws IOException {
List<String> names = new ArrayList<String>();
for (URL url : getResources(path)) {
names.addAll(list(url,path));
}
return names;
}
即 获取某一路劲下及其子节点下的 Resouce,同时, 其用了单例模式来提供实例给外部接口调用:
/** The built-in implementations. */
public static final Class<?>[] IMPLEMENTATIONS = { JBoss6VFS.class, DefaultVFS.class };
/** The list to which implementations are added by{@link #addImplClass(Class)}. */
public static final List<Class<? extends VFS>> USER_IMPLEMENTATIONS = new ArrayList<Class<? extends VFS>>();
/** Singleton instance. */
private static VFSinstance;
/**
* Get the singleton {@link VFS} instance. If no{@link VFS} implementation can be found for the
* current environment, then this method returns null.
*/
@SuppressWarnings("unchecked")
public static VFS getInstance() {
if (instance !=null)
return instance;
// Try the user implementations first, then the built-ins
List<Class<? extends VFS>> impls = new ArrayList<Class<? extends VFS>>();
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.newInstance();
if (vfs == null || !vfs.isValid()) {
log.debug("VFS implementation " +impl.getName() +
" is not valid in this environment.");
}
} catch (InstantiationException e) {
log.error("Failed to instantiate " +impl,e);
return null;
} catch (IllegalAccessException e) {
log.error("Failed to instantiate " +impl,e);
return null;
}
}
log.debug("Using VFS adapter " +vfs.getClass().getName());
return VFS.instance =vfs;
}
/**
* Adds the specified class to the list of {@link VFS} implementations. Classes added in this
* manner are tried in the order they are added and before any of the built-in implementations.
*
* @param clazz The {@link VFS} implementation class to add.
*/
public static void addImplClass(Class<? extends VFS> clazz) {
if (clazz != null)
USER_IMPLEMENTATIONS.add(clazz);
}
可以看到,外部类 可以 自己 编写 相应的 VFS实现类,并调用 addImplClass 将 自己实现类 加入到USER_IMPLEMENTATIONS list中,并在getInstance 方法中,能够保证 自己实现的类 被先用到,当然,如果没有自己实现,mybatis会用默认的JBoss6VFS.class, DefaultVFS.class中的一个,当然,如果想了解 DefautlVFS 和JBoss6VFS 的可以花时间看看,看其是怎么 从 jar包中读取Resouce的,要注意哪些事情,当然,以后如果用到,也可以想到 mybatis已经实现了,可以覆用!
4. ExternalResources
. 利用 jdk1.7新特性 closeable 接口 关闭FileChannel, 同时 利用 nio的FileChannel实现 了 文件的拷贝,将 文件 内容从souceFile 拷贝到 destFile
. getConfiguredTemplate(StringtemplatePath, StringtemplateProperty) 从 某一份Properties 文件中获取 某一个 属性的值
5. ResolverUtil
在提供的包名或者其子节点下的路劲下寻找符合一定条件的 class, 包括 是否 实现 或者 继承 某一个类, 或者 这个类是否被某一个 annotation 标识了,其中最重要的 无非是:
. parent.isAssignableFrom(type); // 可以 对比 instanceof , 了解其区别
. type.isAnnotationPresent(annotation); // 判断 type 是否被annotation 注解了
提供的接口如下:
/**
* Attempts to discover classes that are assignable to the type provided. In the case
* that an interface is provided this method will collect implementations. In the case
* of a non-interface class, subclasses will be collected. Accumulated classes can be
* accessed by calling {@link #getClasses()}.
*
* @param parent the class of interface to find subclasses or implementations of
* @param packageNames one or more package names to scan (includingsubpackages) for classes
*/
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;
}
/**
* Attempts to discover classes that are annotated with the annotation. Accumulated
* classes can be accessed by calling {@link #getClasses()}.
*
* @param annotation the annotation that should be present on matching classes
* @param packageNames one or more package names to scan (includingsubpackages) for classes
*/
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;
}
/**
* Scans for classes starting at the package provided and descending intosubpackages.
* Each class is offered up to the Test as it is discovered, and if the Test returns
* true the class is retained. Accumulated classes can be fetched by calling
* {@link #getClasses()}.
*
* @param test an instance of {@link Test} that will be used to filter classes
* @param packageName the name of the package from which to start scanning for
* classes, e.g. {@code net.sourceforge.stripes}
*/
public ResolverUtil<T> find(Test test, String packageName) {
String path = getPackagePath(packageName);
try {
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;
}