一个类加载器是一个负责加载类的对象,给定一个类的二进制名称,类加载器尝试查找或生成组成该类定义的数据信息。典型的是将这个名称转换成文件名称然后从文件系统中读取类文件
每一个类对象包含一个定义它的类加载器。数组类的类对象不是通过类加载器创建;由java runtime时的需要自动创建。对于一个数组类的类加载器,返回与其元素类的加载器相同;若元素类型为基本类型,那么数组类没有类加载器
应用程序实现子类化的类加载器为了扩展jvm动态加载类的方法。类加载器通常通过安全管理表示安全域的方式被使用。
类加载器的类使用一个代理模型搜索类和资源,每一个类加载器的实例都有一个关联的父类加载器,当需要查找一个类or资源,一个类加载器实例将代理其父类加载器在尝试查找到该类or资源之前。JVM内置加载器“bootstrap class loader”,通常作为其他类加载器的父类加载器。
并行的类加载器支持并发加载类并且要求它们的类在初始化的时调用registerAsParallelCapable进行登记。注意,默认通过登记并行的类加载器,它的子类如需要是并行的时,还是需要进行登记。
在环境中的代理模型是不严格分层的。类加载器需要并行能力,否则可能导致死锁,因为类加载器在类加载过程时持有锁。
通常情况下,JVM从一个平台依赖性的本地文件系统加载类。eg在UNIX系统中,JVM从通过环境变量CLASSPATH定义的目录加载类,然而有些类不是来源一个文件(eg:网络or通过应用程序构建的)。defineClass方法将字节数组转换为类对象的实例,这个新定义的类就可以创建使用newInstance。对象的构造器与行为通过一个类加载器可能引用其他类来创建,确定类涉及到,JVM调用原来创建该类的类加载器的方法loadClass。eg:一个应用创建一个网络类加载器处理从服务器上下载的类文件
ClassLoader loader = new NetWorkClassLoader(host, port);
Object main = loader.loadClass(“Main”, true).newInstance();
网络类加载器子类必须定义findClass、loadClassData方法从网络加载一个类。一旦下载组成该类的字节,应该使用defineClass方法创建一个类对象的实例
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
}
在类加载器的方法中,任何类名被设置为类的二进制名称字符串的参数,eg:有效的类名
java.lang.String
javax.swing.JSpinner$DefaultEditor
java.security.KeyStore$Builder$FileBuilder$1
java.net.URLClassLoader$3$1
包装访问多个类加载器使其作为一个类加载器访问
由于类加载器实现方式不同,我们可能需要向不同的类加载器查找某一个类or资源,所以提供一个包装器实现
public class ClassLoaderWrapper {
ClassLoader defaultClassLoader;
ClassLoader systemClassLoader;//typically the class loader used to start the application
ClassLoaderWrapper() {
try {
systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (SecurityException ignored) {
}
}
//get a resource as a url using the current class path
public URL getResourceAsURL(String resource) {
return getResourceAsURL(resource, getClassLoaders(null));
}
public URL getResourceAsURL(String resource, ClassLoader cl) {
return getResourceAsURL(resource, getClassLoaders(cl));
}
URL getResourceAsURL(String resource, ClassLoader[] cls) {
URL url;
for(ClassLoader cl: cls) {
if(cl != null) {
url = cl.getResource(resource);
if(url == null) url = cl.getResource("/" + resource);
if(url != null) return url;
}
}
return null;
}
//get a resource as a input stream using the current class path
public InputStream getResourceAsStream(String resource) {
return getResourceAsStream(resource, getClassLoaders(null));
}
public InputStream getResourceAsStream(String resource, ClassLoader cl) {
return getResourceAsStream(resource, getClassLoaders(cl));
}
InputStream getResourceAsStream(String resource, ClassLoader[] cls) {
for(ClassLoader cl: cls) {
if(cl != null) {
InputStream in = cl.getResourceAsStream(resource);
if(in == null) in = cl.getResourceAsStream("/" + resource);
if(in != null) return in;
}
}
return null;
}
//find a class on the classpath
public Class<?> classForName(String name) throws ClassNotFoundException {
return null;
}
public Class<?> classForName(String name, ClassLoader cl) throws ClassNotFoundException {
return null;
}
Class<?> classForName(String name, ClassLoader[] cls) throws ClassNotFoundException {
for(ClassLoader cl: cls) {
if(cl != null) {
try {
Class<?> c = Class.forName(name, true, cl);
if(c != null) return c;
} catch (ClassNotFoundException e) {
// we'll ignore this until all classloaders fail to locate the class
}
}
}
throw new ClassNotFoundException("Cannot find class: " + name);
}
ClassLoader[] getClassLoaders(ClassLoader cl) {
return new ClassLoader[] {
cl,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader
};
}
}
来源:oschina
链接:https://my.oschina.net/u/235969/blog/209230