mybatis基础支持层-资源加载模块
一、ClassLoader
- java虚拟机中类加载器,负责加载来自文件、网络或者其他来源的类文件
- 默认的类加载器有三种
- Bootstrap ClassLoader : 负责加载 jdk中的rt.jar中的类文件
- Extension ClassLoader :负责加载jre扩展类库,位于jre/lib/ext下的类文件,或者java.ext.dirs指定的目录下的类文件
- System ClassLoader(Application ClassLoader): 负责加载classpath环境中的类文件,通常是通过-classpath -cp 或者JAR中Manifest文件的classpath属性指定的
- 类加载器遵循双亲委派:遵循自底向上检测类是否加载过,自顶向下尝试加载类
- 双亲委派保证: 子类加载器可以使用父类加载过的类,而父类加载器无法使用子类加载过的类。父类加载过得类子类无法重新加载,保证了JVM的稳定性和安全性
- 要加载一个类,自定义类加载器1将加载类的工作委托给应用加载器,应用加载器首先看是否自己加载过,如果加载过则加载过程结束,没有加载过则继续向上委托二级父类加载器,如果未加载则继续向上传递,一级父类加载器如果未加载过,则从指定目录尝试加载类,如果加载失败,则向下交由二级父类加载器,如果继续加载失败,向下直至加载请求的子加载器为止
(顶) Bootstrap ClassLoader 一级父类加载器
|
|
Extension ClassLoader 二级父类加载器
|
|
System ClassLoader(Application ClassLoader) 应用加载器
|
| |
| --- |
(底) 自定义类加载器1 自定义类加载器2...
- 继承java.lang.ClassLoader可以实现自己的类加载器,修改内部加载的逻辑。Tomcat\Jboss都涉及自定义类加载器
二、Tomcat中的类加载器
-
包含自定义的一个Common ClassLoader,它的父加载器是System ClassLoader,负责加载Tomcat通用的一些类和JAR,例如CATALINA_HOME/lib下的jar包
-
Tomcat还会提供CatalinaLoader 和 SharedLoader 两个加载器,通过配置文件指定加载的目录,默认为空,因而这两个类加载器默认情况与Common ClassLoader为同一个类加载器
-
Tomcat会为每一个应用添加一个WebApp ClassLoader ,其父类加载器是Common ClassLoader ,也就是默认可以加载JDK中的类文件,复杂加载指定应用WEB-INF/lib下的jar包和WEB-INF/classes的类文件
-
由于每个应用都有自己的类加载器,保证了应用之间的资源隔离,采用热部署的时候,会抛弃原来的WebApp ClassLoader创建新的,由于WebApp classLoader 的父加载器都是Common ClassLoader, 因而能够共享Common ClassLoader加载的类库
System ClassLoader
|
|
|
Common ClassLoader
|
| |
| --- | |
WebApp ClassLoader1 WebApp ClassLoader2 WebApp ClassLoader3
三、Mybatis IO包
1. ClassLoaderWrapper
- IO包中提供了ClassLoaderWrapper 是ClassLoader的包装器,内含多个Class Loader,可以调整类加载器的顺序,可以保证提供给系统使用的是正确的类加载器
class ClassLoaderWrapper{
//默认的类加载器
ClassLoader defaultClassLoader;
//系统的类加载器
ClassLoader systemClassLoader;
ClassLoaderWrapper() {
try {
//初始化系统的classloader
systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (SecurityException ignored) {
// AccessControlException on Google App Engine
}
}
}
- class loader列表
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader, //传递过来的类加载器
defaultClassLoader, //默认的类加载
Thread.currentThread().getContextClassLoader(),//当前上下文的类加载器
getClass().getClassLoader(), //当前类类加载器
systemClassLoader}; //提供的类加载器
}
- 主要提供几个核心方法:getResourceAsURL、getResourceAsStream、classForName
URL getResourceAsURL(String resource, ClassLoader[] classLoader) {
URL url;
for (ClassLoader cl : classLoader) {
if (null != cl) {
// look for the resource as passed in...
//通过getResource 获取url
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
//如果URL为空,如果没有的话继续通过 / 的目录去查找资源
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) {
//如果url存在则返回
return url;
}
}
}
// didn't find it anywhere.
return null;
}
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
//与getResourceAsURL 类似,调用ClassLoader的 getResourceAsStream 方法
for (ClassLoader cl : classLoader) {
if (null != cl) {
// try to find the resource as passed
InputStream returnValue = cl.getResourceAsStream(resource);
// now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
//通过Class.forName查找对应名称的类
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);
}
- Resources内部有一个静态变量ClassLoaderWrapper,Resources 内部的方法都是调用ClassLoaderWrapper的相关方法实现的
2.ResolverUtil
根据指定条件到指定包下的类,使用的条件使用Test接口表示 内含一个classloader,默认使用上下文的类加载器,也可以setClassloader设置 Test接口有两个实现,isA用于检测类是否继承指定类和接口,AnnotatedWith用于检测类是否添加了指定注解 也可自定义实现Test接口实现自定义的检测项,Test中的matches方法用于判断是否符合条件
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.
*
* @param type
* the type
* @return true, if successful
*/
boolean matches(Class<?> type);
}
/**
* A Test that checks to see if each class is assignable to the provided class. Note
* that this test will match the parent type itself if it is presented for matching.
* 判断是否类继承了指定的类或接口
*/
public static class IsA implements Test {
/** The parent. */
//绑定父类
private Class<?> parent;
/**
* Constructs an IsA test using the supplied Class as the parent class/interface.
* 注入父类
* @param parentType
* the parent type
*/
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();
}
}
/**
* A Test that checks to see if each class is annotated with a specific annotation. If it
* is, then the test returns true, otherwise false.
* 判断类是否使用了指定注解
*/
public static class AnnotatedWith implements Test {
/** The annotation. */
//绑定注解
private Class<? extends Annotation> annotation;
/**
* Constructs an AnnotatedWith test for the specified annotation type.
* 注入注解
* @param annotation
* the annotation
*/
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();
}
}
...
}
- 使用Test接口相关方法
public ResolverUtil<T> findImplementations(Class<?> parent, String... packageNames) {
if (packageNames == null) {
return this;
}
//查找类的实现,创建Test实现isA
Test test = new IsA(parent);
for (String pkg : packageNames) {
//传入test 查找包下的所有类,加载类,调用test.matches检测是否符合要求
find(test, pkg);
}
return this;
}
public ResolverUtil<T> findAnnotated(Class<? extends Annotation> annotation, String... packageNames) {
if (packageNames == null) {
return this;
}
//查找类是否使用注解,创建Test实现AnnotatedWith
Test test = new AnnotatedWith(annotation);
for (String pkg : packageNames) {
//传入检测方法test,查找包下所有类,加载类,调用test.matches检测是否符合要求
find(test, pkg);
}
return this;
}
3.单例模式
- 单例模式:环境中有且仅有一个实例对象
- 优点:
- 1.避免频繁地创建对象
- 2.减少了GC次数
- 3.节省内存资源
- 4.加快对象访问速度
- 单例例子
//懒汉,延迟加载,get的时候才去初始化,对于创建对象会消耗比较多资源的情况比较适用
public class Singleton {
private static Singleton instance=null;
private Singleton() {};
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
//饿汉,
public class Singleton {
private static Singleton instance=null;
private Singleton() {};
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
//双重校验锁
//volatile syschronized 进行双重校验
public class Singleton {
public volatile Singleton _INSTANCE = null;
public Singleton getInstance(){
if(_INSTANCE == null){
synchronized (Singleton.class){
if(_INSTANCE == null){
_INSTANCE = new Singleton();
}
}
}
return _INSTANCE;
}
}
//内部类
//类加载机制保证只创建一个对象。
//第一次访问类中静态字段时就触发类的加载,并且同一个类只加载一次。
//由类加载器负责加锁,保证线程安全
//因而内部类的方法会比双重校验锁更加简洁,也同样安全
public class Singleton{
private Singleton() {};
private static class SingletonHolder{
private static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
//枚举类
- 更多单例实例,请参考code
5.VFS
- VFS Virtual File System 用来查找指定路径下的资源
- Mybatis中提供了JBoss6VFS DefaultVFS的两个实现