类加载——双亲委派机制


先说说什么是类加载器

  • 类加载器是Java虚拟机提供给应用程序去实现和获取类和接口字节码的技术,用于动态加载Java类到内存中(将字节码转换为byte[ ])的组件

四种类加载器

  1. 启动类加载器(Bootstrap ClassLoader),加载核心类,比如String类
  2. 扩展类加载器(Extension ClassLoader),加载扩展类
  3. 应用程序类加载器(Application ClassLoader),加载classpath中的类
  4. 自定义类加载器,一般重写findClass方法

注: JDK9之后扩展类加载器 (Extension ClassLoader) 变为平台类加载器 (Platform ClassLoader)


什么是双亲委派机制

  • 每个Java实现的类加载器中都有一个属性,可以理解为存放的是其父类加载器

    在这里插入图片描述

启动类加载器是用本地代码,通常是C/C++写的,所以用java代码不能获取,结果返回为null,所以扩展类的parent属性是null,但是逻辑上来说启动类加载器还是相当于它的父类
JDK9引入了module的概念,类加载器在设计上发生很大改变,启动类加载器使用java编写,不过仍然无法通过java代码获取到,返回依然是null

流程概述

  • 自底向上进行查找: 如果类没有被当前加载器加载过,则查找父类有没有加载过,如果加载过则返回,如果没有则继续向上查找

  • 由顶向下进行加载: 如果直到启动类加载器都没有被加载过,则由父类尝试加载,再由子类尝试,直到被加载并返回

双亲委派机制的好处

  1. 防止类的重复加载:通过双亲委派机制,每个类加载器在加载类时都会委派给其父加载器,因此可以避免同一个类被多个加载器加载,保证了类的唯一性
  2. 保护类的安全性:双亲委派机制可以防止恶意类的加载,即使是恶意类也无法绕过双亲委派机制直接被加载,它们必须被放置在被信任的类路径下才能被加载
  3. 保护核心类库的完整性:通过双亲委派机制,Java核心类库(如java.lang包)被放置在引导类加载器的类路径下,这样可以保护核心类库的完整性,防止被篡改或替换,确保了Java运行环境的稳定性和安全性

ClassLoader源码简单分析

  • ClassLoader中有几个重要方法

    1.类加载的入口,提供双亲委派机制,内部调用findClass
    loadClass(String):Class<?>

    2.类加载器子类实现,获取二进制数据调用defineClass
    findClass(String):Class<?>

    3.做类名校验,调用虚拟机底层方法将字节码加载到内存
    defineClass(String, byte[], int, int):Class<?>

    4.执行类生命周期连接阶段
    resolveClass(Class<?>):void

  • ClassLader的loadClass方法

//1.String name 被加载类名
protected Class<?> loadClass(String name, boolean resolve)  
    throws ClassNotFoundException  
{  
    //2,加锁防止在多线程条件下重复加载类
    synchronized (getClassLoadingLock(name)) 
    {  
        //3,查找此类是否被加载过,若被加载则返回Class对象
        Class<?> c = findLoadedClass(name);  
        //4,如果c为空,则说明未被加载过,否则,是被加载过,跳到10
        if (c == null) {  
            long t0 = System.nanoTime();  
            try {  
                //5,判断父类加载器是否为null
                if (parent != null) {
                    //6,如果不为空,则调用父类loadClass方法  
                    c = parent.loadClass(name, false);  
                } 
                else {  
                    //7,如果为空,说明父类为启动类加载器,调用本地方法来加载
                    c = findBootstrapClassOrNull(name);  
                }  
            } 
            catch (ClassNotFoundException e) {  
            }  

            //8,如果c为空,说明其父类都没有加载成功,则由当前类加载器来进行加载
            if (c == null) {
            
            //9,加载类  
                c = findClass(name); 
                 
                PerfCounter.getParentDelegationTime().addTime(t1 - t0);  
                PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);  
                PerfCounter.getFindClasses().increment();  
            }  
        }  
        
        if (resolve) {  
            resolveClass(c);  
        }  
        
        //10,返回Class对象
        return c;  
    }  
}

打破双亲委派机制的方式

  1. 自定义类加载器,重写loadClass方法,不再实现双亲委派机制
  2. JNDI,JDBC,JCE,JAXB 和 JBI 等框架使用了SPI机制+线程上下文类加载器
  3. OSGI 允许同级类加载器相互调用
  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值