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

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

作者: 糯米团子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);
    
            // 省略部分代码
    
        }
    }
    
    

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

    相关文章

      网友评论

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

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