美文网首页
为什么打破双亲委派模型?

为什么打破双亲委派模型?

作者: 糯米团子123 | 来源:发表于2022-08-23 17:29 被阅读0次
  1. 双亲委派模型:如果一个类加载器收到了类加载请求,他并不会自己先去加载,而是把这个请求委托给父类加载器,父类加载器还存在父类加载器则进一步向上委托,依次递归,请求最终到达顶层启动类加载器。如果父类加载器可以完成类加载任务,就成功返回,父类加载器无法完成加载任务,则子类加载器会尝试自己去加载。

  2. 双签委派模型优缺点:
    2.1 优点
    避免重复加载,确保类的全局唯一性
    保护程序安全,防止核心api被随意篡改
    2.2 缺点
    由于加载范围限制,顶层的ClassLoader无法访问底层的ClassLoader所加载的类。

  3. 为什么要破坏双亲委派模型?
    由于加载范围的限制,顶层的ClassLoader无法访问底层ClassLoader所加载的类,此时需要破坏双亲委派模型。

  4. 以JDBC为例
    4.1 不使用java SPI时,以如下方式加载驱动实现类:
    在Driver类中像DriverManager注册对应的驱动实现类。

Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.
getConnection("jdbc:mysql://myhost/test?useUnicode=true&characterEncoding=utf-8&useSSL=false", "test", "test");

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

4.2 使用java SPI
JDBC4.0以后,开始支持使用SPI的方式来注册Driver,具体做法:在Mysql的jar包中的META-INF/services/java.sql.Driver文件中指明当前使用的Driver是哪个。
SPI:策略模式,根据配置决定运行时的接口实现类是哪个。当使用不同驱动时候,我们不需要手动通过Class.forName加载驱动类,只需要引入相应jar即可。

Connection conn = DriverManager.
getConnection("jdbc:mysql://myhost/test?useUnicode=true&characterEncoding=utf-8&useSSL=false", "test", "test");

4.2.1 驱动类何时加载?

  • 从META-INF/services/java.sql.Driver文件中获取具体的实现类“com.mysql.jdbc.Driver”
  • 通过Class.forName(“com.mysql.jdbc.Driver”)将这个类加载进来
  • DriverManager在rt.jar包中,所以DriverManager是通过启动类加载器加载进来的。而Class.forName()加载的调用者是ClassLoader,所以如果用启动类加载器加载com.mysql.jdbc.Driver 肯定是加载不到的。
    4.2.2 解决办法
    破坏双亲委派模型。
    让顶层类加载器加载底层类加载器。
public class DriverManager {

    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }

    private static void loadInitialDrivers() {

        // 省略部分代码
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {

                // 根据配置文件加载驱动实现类
                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();

                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });

        // 省略部分代码
    }

}


ServiceLoader:通过执行Thread.currentThread().getContextClassLoader()获取了线程上下文加载器

// ServiceLoader#load
public static <S> ServiceLoader<S> load(Class<S> service) {

    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    return ServiceLoader.load(service, cl);
}

ExtClassLoader和AppClassLoader都是通过Launcher类来创建的,在Launcher类的构造函数中,可以看到线程上下文类加载器默认设置了AppClassLoader

public class Launcher {

    public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }

        // 设置线程上下文类加载器为AppClassLoader
        Thread.currentThread().setContextClassLoader(this.loader);

        // 省略部分代码

    }
}

线程上下文类加载器让父类加载器能通过调用子类加载器来加载类,这打破了双亲委派模型的原则

相关文章

  • 2018-07面试题目

    1. JVM的类加载机制 主要是双亲委派模型的东西。它是什么、怎么工作的、为什么要有它,以及打破双亲委派模型的...

  • Java 类加载

    双亲委派模型 并非强制 而是推荐 SPI 父类加载器需要子类加载器加载类 打破双亲委派模型 https://www...

  • 为什么打破双亲委派模型?

    双亲委派模型:如果一个类加载器收到了类加载请求,他并不会自己先去加载,而是把这个请求委托给父类加载器,父类加载器还...

  • SPI的ClassLoader问题

    问题 为什么说spi服务机制破坏了双亲委派模型? 双亲委派机制 启动类加载器(Bootstrap ClassLoa...

  • Tomcat类载入器

    大家都知道,Java的类加载机制是双亲委派模型,那么什么是双亲委派模型呢?我们这里简要的说一下,双亲委派模型...

  • JVM类加载过程详细分析

    双亲委派加载模型 为什么需要双亲委派加载模型 主要是为了安全,避免用户恶意加载破坏JVM正常运行的字节码文件,比如...

  • java类加载破坏双亲委派模型

    前面java类加载器与双亲委派模型中提到Java采用个双亲委派的方式来完成类加载,但是双亲委派模型并不是一个强制的...

  • java 详解类加载器的双亲委派及打破双亲委派

    java 详解类加载器的双亲委派及打破双亲委派 https://blog.csdn.net/Dopamy_Busy...

  • sandBox源码分析之ClassLoader

    提起classLoader,就不由自主想起了java classLoader的双亲委派模型,那么到底什么是双亲委派...

  • 双亲委派模型

    一、类加载器简介:JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构: Bootstrap ClassL...

网友评论

      本文标题:为什么打破双亲委派模型?

      本文链接:https://www.haomeiwen.com/subject/khdggrtx.html