JVM类加载器的认识
对类的加载器进行认识:
public class ClassLoaderTest { public static void main(String[] args) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); System.out.println(loader); System.out.println(loader.getParent()); System.out.println(loader.getParent().getParent()); } }
sun.misc.Launcher$AppClassLoader@64fef26a sun.misc.Launcher$ExtClassLoader@1ddd40f3 null会发现,找到了ApplicationClassLoader和ExtClassLoader,但是没有找到ExtClassLoader的父加载器BootstrapClassLoader,原因是BootstrapClassLoader使用C语言实现的,并不是用java语言做的,所以是不能返回一个确定的父加载器的方法,所以才返回了NULL。
而在Java中,类加载器的结构为:
注意:这里的父类加载器并不是通过集成的方式来实现的,而是通过类组合的方式实现的。
类加载器大致分为三类:
第一、启动类加载器。(BootStrapt ClassLoader)
启动类加载器,负责加载存放在JDK/jre/lib目录下的类库,比如:rt.jar。启动类加载器是无法被Java程序直接引用的。
第二、扩展类加载器。(Ext ClassLoader)
扩展类加载器,负责加载JDK/jre/lib/ext目录下的所有类库。开发者是可以直接使用扩展类加载器。
第三、应用程序类加载器。(Application ClassLoader)
应用程序类加载器,负责加载用户类路径(classpath)所指定的类,开发者可以直接使用该类加载器,如果引用程序没有自定义过自己的类加载器,一般情况这就是程序默认的类加载器。
同时,可以实现自定义类加载器:
通常情况下,我们都是直接使用系统自带的类加载器。但是,有的时候,我们也需要自定义类加载器。那图和实现呢?
自定义类加载器一般都是继承自ClassLoader类,从上面对loadClass方法来分析看,只需要重写findClass方法即可。
自定义类加载器的应用场景:比如对字节码进行了加密之后,可以通过自定义类加载器来实现解密。
package com.hui; import java.io.*; public class MyClassLoader extends ClassLoader { private String root; protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = loadClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { return defineClass(name, classData, 0, classData.length); } } private byte[] loadClassData(String className) { String fileName = root + File.separatorChar + className.replace('.', File.separatorChar) + ".class"; try { InputStream ins = new FileInputStream(fileName); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int length = 0; while ((length = ins.read(buffer)) != -1) { baos.write(buffer, 0, length); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } public String getRoot() { return root; } public void setRoot(String root) { this.root = root; } public static void main(String[] args) { MyClassLoader classLoader = new MyClassLoader(); classLoader.setRoot("E:\\temp"); Class<?> testClass = null; try { testClass = classLoader.loadClass("com.neo.classloader.Test2"); Object object = testClass.newInstance(); System.out.println(object.getClass().getClassLoader()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }