java双亲委派机制及作用

double

记录一下

双亲委派机制工作过程:

  1. 类加载器收到类加载器的请求;
  2. 把这个类委托给父级加载类去完成,一直向上委托直到启动类加载器;
  3. 启动类检查能不能加载(使用 findClass 方法),能就加载(结束),否责抛出异常,通知子加载器进行加载;
  4. 重复步骤3;

双亲委派机制的作用

  1. 防止内存中出现多份同样的字节码,通过委托向上级询问是否加载过,如果加载过了就不需要加载,保证类的唯一性。
  2. 保证核心 .class 文件不被篡改,通过委托方式不会去篡改核心 .class ,即使篡改了也不会去加载,这样保证了 Class 执行安全。

类加载器的类别

一、启动类加载器(引导类加载器,Bootstrap ClassLoader),虚拟机自带的加载器

  1. 该类加载使用 C/C++ 语言实现的,嵌套在JVM中。
  2. 它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar或sub.boot.class.path路径下的目录),用于提供JVM自身需要的类。
  3. 并不继承自 java.lang.ClassLoader,没有父加载器。
  4. 加载【扩展类】、【应用程序类】,并指定为它们的父类加载器。
  5. 出于安全考虑,Bootstrap 启动类加载器只会加载包名为 java、javax、sun等开头的类

二、扩展类加载类(Extension ClassLoader),虚拟机自带的加载器

  • Java语言编写,由 sun.misc.Launcher$ExtClassLoader实现
  • 派生于ClassLoader类
  • 父类加载器为【启动类加载器】
  • 从 java.ext.dirs 系统属性所指定的目录中加载类库,或从JDK的安装目录的 jre/lib/ext子目录下加载类库,如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载

三、应用程序类加载器(系统类加载器,AppClassLoader)

  1. java语言编写,由 sun.misc.Launcher$AppClassLoader实现
  2. 派生于 ClassLoader 类
  3. 父类加载器为扩展类加载器
  4. 它负责加载环境变量下 classpath 或系统属性 java.class.path 指定路径下的类库
  5. 该类加载是程序中默认的类加载器,一般来说 Java应用的类都是由它来完成加载
  6. 通过 ClassLoader#getSystemClassLoader() 方法可以获取到该类加载器

四、用户自定义类加载器

在java日常开发中,类的加载几乎都是由以上3种类加载器相互配合执行的,在必要的时候我们可以自定义类加载器,来定制类的加载方式

为什么要自定义类加载器?

  1. 隔离加载类(主要场景是在中间件开发中类名和项目中类名相同)
  2. 修改类的加载方式
  3. 扩展加载源
  4. 防止源码泄漏
/** * @author xiaofei.yan * @Descript 自定义类加载器 * loadByte: 方法仅用作读取文件 * findClass 方法才是加载类到内存中,PS: name 必须填全限定名,比如 java.lang.Object */ public class MyClassLoader extends ClassLoader { /** * 保存的地址 */ private String classPath; /** * 传入地址构造函数 * @param classPath */ public MyClassLoader(String classPath) { this.classPath = classPath; } /** * 读取 class 文件 */ private byte[] loadByte(String name) throws Exception { String inPath = classPath + "/" + name + ".class"; FileInputStream fis = new FileInputStream(inPath); // 返回字节码长度 int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } /** * 重写 findClass 方法,让加载的时候调用 findClass 方法 */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException{ try { byte[] data = loadByte(name); // 将字节码载入内存 return defineClass(name, data, 0 ,data.length); } catch (Exception e) { e.printStackTrace(); } return null; } }