类加载机制之双亲委派模型、作用、源码、SPI打破双亲委派模型

双亲委派模型

        • 双亲委派工作机制
        • 双亲委派的作用
        • 双亲委派的实现源码
        • SPI打破双亲委派

应用程序是由三种类加载器相互配合,从而实现类加载,除此之外还可以加入自己定义的类的加载器。

类加载器之间的层次关系,称为双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其他的类加载器都要有自己的父类加载器。这里的父类关系一般通过组合关系(Composition)来实现,而不是继承关系(Inheritance)。

类加载机制之双亲委派模型、作用、源码、SPI打破双亲委派模型_第1张图片

双亲委派工作机制

一个类加载器首先将类加载请求转发到父类加载器,只有当父类加载器无法完成时菜尝试自己加载。

双亲委派的作用
  1. 每个类只会加载一次,解决了各个类加载器加载基础类的统一问题(基础类库由上层的加载器进行加载)
  2. 防止恶意破坏的类加载,内存中不会出现多份同样的字节码的系统类iii,保证Java程序安全稳定运行。

例如:java.lang .object存放在rt.jar中,如果编写另外—个java.lang.Object并放到ClassPath 中,程序可以编译通过。由于双亲委派模型的存在,所以在rt.jar中的Object比在ClassPath 中的 Object 优先级更高,因为rt.jar中的object使用的是启动类加载器,而ClassPath中的 object使用的是应用程序类加载器。rt.jar中的Object优先级更高,那么程序中使用的所有的 Object都是由启动类加载器所加载的Object 。

双亲委派的实现源码

以下是抽象类 java.lang.ClassLoader的代码片段,其中的loadClass()方法运行过程如下:先检查类是否已经加载过,如果没有则让父类加载器去加载。当父类加载器加载失败时抛出 ClassNotFoundException,此时尝试自己去加载。

public abstract class ClassLoader{
    //The parent class loader for delegation
    private final ClassLoader parent;
    
    public Class<?> loadClass(String name) throws ClassNotFoundException{
        return loadClass(name,false);
    }
    
    protected Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException{
        synchronized (getClassLoadingLock(name)){
            //First,check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if(c == null){
                try{
                    if (parent != null){
                        c = parent.loadClass(name,false);
                    }else{
                        c = findBootstrapClassOrNull(name);
                    }
                }catch (ClassNotFoundException e){
                     //ClassNotFoundException thrown if class not foundl from the non-null parent class loader
                }
                
                if (c == null){
                    // If still not found,then invoke findclass in orderll to find the class.
					c = findClass(name);
                }
            }
            if(resolve){
                resolveClass(c);
            }
            return c;
        }
    }
    protected Class<?> findClass(String name) throws ClassNotFoundException{
        throw new ClassNotFoundException(name);
    }
}
SPI打破双亲委派

SPI(Service Provider Interface),是一种服务发现机制,它通过在ClassPath路径下的META-INF/ services文件夹查找文件,自动加载文件里所定义的类。
如下图,SPI核心类定义在rt.jar中(例如:java.lang.Driver接口),所以java.lang.Driver接口本身是由启动类加载器加载,当调用java.lang.Driver接口的实现类时,启动类加载器是无法加载实现类的,这个时候就提供了线程上下文类加载器(Thread context ClassLoader )加载实现类,ThreadcontextClassLoader是可以通过 java.lang.Thread #setcontextclassLoader方法设置类加载器,这样就打破了双亲委派的类加载模式。
类加载机制之双亲委派模型、作用、源码、SPI打破双亲委派模型_第2张图片

你可能感兴趣的:(JVM,jvm)