1. ClassLoader介绍
ClassLoader是将字节码加载进JVM内存中的类,同时将解析并初始化类,sun默认提供的有三个ClassLoader。
2. 双亲委托机制原因
正确加载程序和JVM所需要的类,比如String类是由Bootstrap ClassLoader加载的,要是没有双亲委托机制,而我自己又编写了一个String类,那么将会加载我的String进入JVM中,此时其他依赖的类用到了系统的String类的话,就可能会出现错误,有两个String类被加载进了JVM中,可能会导致无法运行成功,双亲委托就是保证这种情况不会发生。
3. 三个ClassLoader
Bootstrap ClassLoader
不继承自ClassLoader,由C++实现,随JVM启动而加载,会构造出ExtClassLoader和AppClassLoader;加载rt.jar包中的class
ExtClassLoader
父类是Bootstrap ClassLoader,但因为Bootstrap是c++编写的,所以在java中用null表示ExtClassLoader的父类加载器;加载ext文件夹中的class
AppClassLoader
父类是ExtClassLoader,加载用户所编写的Class
4. 类加载动态性
JVM启动时,将所需要的基础类都加载到内存中来(Bootstrap),而其他类只在需要时才加载,这样能节省内存开销
5. context class loader(基础类中回调用户代码)
线程上下文类加载器:绕过双亲委托模式,指定类加载器。比如JDBC接口是由java核心库提供,而我们使用时是利用其实现类,此时因为实现类不属于java核心库,而JDBC接口里的代码经常需要加载具体的实现类,实现类是由AppClassLoader加载,则会出现问题。context class loader默认是AppClassLoader,使用其则能让SPI接口的代码(如JDBC接口的代码)使用context class loader,从而成功加载到SPI实现的类。
|
|
6. 自定义ClassLoader
- 重写findClass()方法
- 将类字节码文件读取进来
- 用defineClass()方法将加载到jvm1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859public class TestClassLoader extends ClassLoader {String path;String name;public TestClassLoader(String name,String path){super();this.name = name;this.path = path;}public TestClassLoader(ClassLoader parent,String name,String path){super(parent);this.name = name;this.path = path;}protected Class<?> findClass(String name) throws ClassNotFoundException {byte[] data = getDataFromClassFile(name);return defineClass(name, data, 0, data.length);}public byte[] getDataFromClassFile(String name){byte[] returnData = null;name = name.replaceAll("\\.", "/");path = path + name + ".class";InputStream is = null;ByteArrayOutputStream os =null;try{is = new FileInputStream(new File(path));os = new ByteArrayOutputStream();int len;while ((len = is.read()) != -1) {os.write(len);}returnData = os.toByteArray();}catch(Exception e){e.printStackTrace();}finally{try{if(is!=null){is.close();}if(os!=null){os.close();}}catch(Exception e){e.printStackTrace();}}return returnData;}public String toString() {return this.name;}}