类加载器-学习笔记
类加载器
一. jvm架构简图
二. 类加载器
- 类加载器子系统作用
a. 类加载过程
- 加载(Loading):
加载.calss文件的方式:
从本地系统中直接加载
通过网络获取,典型场景:web Applet
从zip压缩包中读取,成为日后jar、war格式的基础
运行时计算生成,使用最多的是:动态代理技术
- 链接(Linking):
-
验证(Verify):
-
准备(Prepare):
-
解析(Resolve):
- 初始化(Initialization):
b. 类加载器的分类
-
JVM支持两种类型的类加载器,分别为引导类加载器(Bootstrap ClassLoader)和自定义加载器(user-defined ClassLoader)
-
从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是java虚拟机规范却没这么定义,而是将所有派生与抽象类ClassLoader的类加载器都划分为自定义类加载器
-
无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有3个
ps:这里的四者之间的关系是包含关系。不是上层下层,也不是父类的继承关系
public class ClassLoaderTest {
public static void main(String[] args) {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2
//获取其上层:扩展类加载器
ClassLoader extClassLoader = systemClassLoader.getParent();
System.out.println(extClassLoader); //sun.misc.Launcher$ExtClassLoader@5cad8086
//获取其上层: 获取不到引导类加载器
ClassLoader bootstrapClassLoader = extClassLoader.getParent();
System.out.println(bootstrapClassLoader); //null
//对于用户自定义类来说:默认使用系统类加载器进行加载
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2
//String 类使用引导类加载器进行加载的---> java的核心类库都是由引导类加载器进行加载的
ClassLoader classLoader1 = String.class.getClassLoader();
System.out.println(classLoader1); //null
}
}
虚拟机自带的加载器
-
启动类加载器(引导类加载器 Bootstrap ClassLoader)
- 这个类加载使用C++语言实现的,嵌套在JVM内部
- 它用来加载JAVA核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类
- 并不继承子java.lang.classLoader,没有父加载器
- 加载扩展类和应用程序类加载器,并制定为他们的父类加载器
- 处于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类
-
扩展类加载器(Extension ClassLoader)
-
应用程序类加载器(系统类加载器 AppClassLoader)
public class ClassLoaderTest1 {
public static void main(String[] args) {
System.out.println("****************启动类加载器****************");
//获取bootstrapClassLoader能够加载的api路径
URL[] urls = sun.misc.Launcher.getBootstrapClasspath().getURLs();
for(URL element:urls){
System.out.println(element.toExternalForm());
}
//从上面的路径中随便选择一个类,来看他的类加载器是什么:引导类加载器
ClassLoader classLoader = Provider.class.getClassLoader();
System.out.println(classLoader); //null
System.out.println("*******************扩展类加载器*****************");
String extDirs = System.getProperty("java.ext.dirs");
for (String path:extDirs.split(";")){
System.out.println(path);
}
//从上面的路径中随便选择一个类,来看他的类加载器是什么:扩展类加载器
ClassLoader classLoader1 = CurveDB.class.getClassLoader();
System.out.println(classLoader1); //sun.misc.Launcher$ExtClassLoader@63947c6b
}
}
public class CustomerClassLoader extends ClassLoader{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException{
try{
byte[] result = getClassFromCustomPath(name);//已二进制流的方式读进内存形成字节数组
if(result == null){
throw new FileNotFoundException();
}else {
return defineClass(name,result,0,result.length);
}
}catch (FileNotFoundException e){
e.printstacktrace();
}
throw new ClassNotFoundException(name);
}
private byte[] getClassFromCustomPath(String name) {
//从自定义路径中加载指定类
//如果指定路径的字节码文件进行了加密,则需再此方法中进行解密操作
return null;
}
public static void main(String[] args) {
CustomerClassLoader customerClassLoader = new CustomerClassLoader();
try {
Class<?> clazz = Class.forName("One",true,customerClassLoader);
Object obj = clazz.newInstance();
System.out.println(obj.getClass().getClassLoader());
} catch (Exception e) {
e.printstacktrace();
}
}
}
c. ClassLoader
- CLassLoader类,它是一个抽象类,其后所有的类加载器都继承自ClassLoader(不包含启动类加载器)
方法名称 | 描述 |
---|---|
getParent() | 返回该类加载器的超类加载器 |
loadClass(String name) | 加载名称为name的类,返回结果为java.lang.class类的实例 |
findClass(String name) | 查找名称为name的类,返回结果为java.lang.class类的实例 |
findLoadedCladd(String name) | 查找名称为name的已经被加载过的类,返回结果为java.lang.class类的实例 |
defineClass(String name, byte[] b,int off, int len) | 把字节数组b中的内容转换为一个java类,返回结果为java.lang.class类的实例 |
resolveClass(Class<?> c) | 链接指定的一个java类 |
sun.misc.Launcher它是一个java虚拟机的入口应用
-
获取ClassLoader的途径
描述 方法 获取当前类的CLassLoader clazz.getClassLoader() 获取当前线程上下文的classLoader Thread.currentThread().getContextClassLoader() 获取系统的classLoader ClassLoader.getSystemClassLoader() 获取调用者的classLoader DriverManage.getCallerClassLoader() public class ClassLoaderTest2 { public static void main(String[] args) { try { //方式一 ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader(); System.out.println(classLoader); //null //方式二 ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader(); System.out.println(classLoader1); //sun.misc.Launcher$AppClassLoader@18b4aac2 //方式三 ClassLoader classLoader2 = ClassLoader.getSystemClassLoader().getParent(); System.out.println(classLoader2); //sun.misc.Launcher$ExtClassLoader@5cad8086 } catch (ClassNotFoundException e) { e.printstacktrace(); } } }