精华内容
下载资源
问答
  • 双亲委派机制

    2020-09-25 07:37:41
    双亲委派机制 双亲委派机制工作原理

    双亲委派机制

     

    双亲委派机制工作原理

    展开全文
  • 通俗易懂的双亲委派机制

    万次阅读 多人点赞 2018-09-27 23:24:08
    在介绍双亲委派机制的时候,不得不提ClassLoader。说ClassLoader之前,我们得先了解下Java的基本知识。 Java是运行在Java的虚拟机(JVM)中的,但是它是怎么就运行在JVM中了呢?我们在IDE中编写的Java源代码被编译器...

    当你超过别人一点点,别人会嫉妒你;当你超过别人一大截,别人就会羡慕你

     

    你得先知道

    在介绍双亲委派机制的时候,不得不提ClassLoader(类加载器)。说ClassLoader之前,我们得先了解下Java的基本知识。  
      Java是运行在Java的虚拟机(JVM)中的,但是它是如何运行在JVM中了呢?我们在IDE中编写的Java源代码被编译器编译成.class的字节码文件。然后由我们得ClassLoader负责将这些class文件给加载到JVM中去执行。  
      JVM中提供了三层的ClassLoader:

    • Bootstrap classLoader:主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和APPClassLoader。

    • ExtClassLoader:主要负责加载jre/lib/ext目录下的一些扩展的jar。

    • AppClassLoader:主要负责加载应用程序的主函数类

      那如果有一个我们写的Hello.java编译成的Hello.class文件,它是如何被加载到JVM中的呢?别着急,请继续往下看。

    双亲委派机制

    我打开了我的AndroidStudio,搜索了下“ClassLoader”,然后打开“java.lang”包下的ClassLoader类。然后将代码翻到loadClass方法:

        public Class<?> loadClass(String name) throws ClassNotFoundException {
            return loadClass(name, false);
        }
        //              -----??-----
        protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
                // 首先,检查是否已经被类加载器加载过
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    try {
                        // 存在父加载器,递归的交由父加载器
                        if (parent != null) {
                            c = parent.loadClass(name, false);
                        } else {
                            // 直到最上面的Bootstrap类加载器
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
    
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        c = findClass(name);
                    }
                }
                return c;
        }

    其实这段代码已经很好的解释了双亲委派机制,为了大家更容易理解,我做了一张图来描述一下上面这段代码的流程:  

     
    从上图中我们就更容易理解了,当一个Hello.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。那么有人就有下面这种疑问了?

    为什么要设计这种机制

    这种设计有个好处是,如果有人想替换系统级别的类:String.java。篡改它的实现,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了(为什么?因为当一个类需要加载的时候,最先去尝试加载的就是BootstrapClassLoader),所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入。

    总结了一张脑图如下:

     

    --->推荐阅读:用最搞笑的漫画讲解HTTPS的原理笑岔气了!<---

     

    想成为Java开发专家,了解这些还远远不够,我这里总结了一些Java知识的史上最全脑图:

    等等等还有五十几张脑图等着你,不光是脑图,知识点的讲解也会在下面的公众号第一时间发布哦,赶紧来关注吧~

    微信搜索:IT烂笔头  或者微信扫描二维码,关注回复【职场】获得作者好友位

     

    展开全文
  • 双亲委派机制 当加载一个类的时候会经过双亲委派机制,一层一层向上询问类是否已经加载了 java中存在三种类加载器 C/C++库编写的引导类加载器BootStrapClassLoader 扩展类加载器ExtensionClassLoader 应用程序类...

    双亲委派机制

    当加载一个类的时候会经过双亲委派机制,一层一层向上询问类是否已经加载了

    java中存在三种类加载器

    • C/C++库编写的引导类加载器BootStrapClassLoader
    • 扩展类加载器ExtensionClassLoader
    • 应用程序类加载器ApplicationClassLoader

    以及自定义的ClassLoader

    当程序中需要加载一个类时,首先会向上传递是否加载了这时就会传递给ExtensionClassLoaderExtensionClassLoader有父类就会接着传递给父类,一直到顶层的BootStrapClassLoaderBootStrapClassLoader会尝试加载类,如果失败,向下传递给ExtensionClassLoader,如果也失败则接着向下传递尝试加载。

    也就是说总的会先文引导类加载器是否加载了,然后一层一层向下的询问。


    沙箱安全机制

    引导类加载器会先加载jdk自带的文件,如果有一个外来类需要加载,并且包名和类名相同,则由于优先由引导类加载了自带的类,所以不会加载这个不符合规范的类,这样保护了java核心源代码,也称沙箱安全机制

    展开全文
  • 双亲委派机制在加载类的时候,会一级一级向上委托,判断是否已经加载,从自定义类加载器-》应用类加载器-》扩展类加载器-》启动类加载器,如果到最后都没有加载这个类,则回去加载自己的类。双亲委托有个弊端:不能...

    双亲委派机制

    在加载类的时候,会一级一级向上委托,判断是否已经加载,从自定义类加载器-》应用类加载器-》扩展类加载器-》启动类加载器,如果到最后都没有加载这个类,则回去加载自己的类。

    双亲委托有个弊端:

    不能向下委派,不能不委派

    怎么打破双亲委派机制:(也就是能向下委派和不委派)

    自定义类加载器(不委派)

    spi机制(向下委派)

    打破双亲委派

    打破双亲委派的两种方式:

    1.通过spi机制,使用ServiceLoader.load去加载

    2.通过自定义类加载器,继承classloader,重写loadclass方法

    SPI机制

    spi机制是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。这一机制为很多框架扩展提供了可能,比如在JDBC中就使用到了SPI机制。

    为什么通过spi机制就能打破双亲委托?

    因为在某些情况下父类加载器需要委托子类加载器去加载class文件。受到加载范围的限制,父类加载器无法加载到需要的文件。

    以Driver接口为例,DriverManager通过Bootstrap ClassLoader加载进来的,而com.mysql.jdbc.Driver是通过Application ClassLoader加载进来的。由于双亲委派模型,父加载器是拿不到通过子加载器加载的类的。这个时候就需要启动类加载器来委托子类来加载Driver实现,从而破坏了双亲委派。

    SPI机制demo:

    public interface HelloService {

    public String getName();

    }

    public class Hello1 implements HelloService{

    @Override

    public String getName() {

    return "hello1";

    }

    }

    public class Hello2 implements HelloService{

    @Override

    public String getName() {

    return "hello2";

    }

    }

    来一个main方法去加载它,将使用ServiceLoader来进行加载

    public class SPITest {

    public static void main(String[] args) {

    ServiceLoader serviceLoader = ServiceLoader.load(HelloService.class);

    for (HelloService helloService :serviceLoader){

    System.out.println(helloService.getName());

    }

    }

    }

    配置文件,文件名为接口的全路径,文件内容为实现类的全路径,如我的为:com.chuan.service.Hello1

    输出结果:hello1

    只配置了Hello1,所以只发现了这一个实现类。

    自定义类加载器

    实现逻辑:自定义类继承classLoader,作为自定义类加载器,重写loadClass方法,不让它执行双亲委派逻辑,从而打破双亲委派。

    先看一个没有重写的demo

    结果:

    sun.misc.Launcher$AppClassLoader@58644d46

    发现是app类加载器。

    然后重写loadClass方法

    public class MyClassLoader extends ClassLoader{

    public static void main(String[] args) throws ClassNotFoundException {

    // ServiceLoader.load()

    MyClassLoader myClassLoader = new MyClassLoader();

    Class> aClass = myClassLoader.loadClass(Test1.class.getName());

    System.out.println(aClass.getClassLoader());

    }

    protected Class> findClass(String className) throws ClassNotFoundException {

    System.out.println("My findClass!");

    return null;

    }

    protected Class> loadClass(String name, boolean resolve)

    throws ClassNotFoundException

    {

    synchronized (getClassLoadingLock(name)) {

    Class> c = findLoadedClass(name);

    if (c == null) {

    long t0 = System.nanoTime();

    try {

    //修改classloader的原双亲委派逻辑,从而打破双亲委派

    if (name.startsWith("com.chuan")){

    c=findClass(name);

    }

    else {

    c=this.getParent().loadClass(name);

    }

    } catch (ClassNotFoundException e) {

    }

    if (c == null) {

    long t1 = System.nanoTime();

    c = findClass(name);

    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);

    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);

    sun.misc.PerfCounter.getFindClasses().increment();

    }

    }

    if (resolve) {

    resolveClass(c);

    }

    return c;

    }

    }

    }

    class Test1{

    }

    运行报错,因为没有委派给app类加载器,所以找不到加载不了这个类。

    那么新的问题又来了,如果我自定义类记载器和核心类重名怎么办,该怎么加载,又或者我想篡改核心类内容,jvm又是怎么解决的?

    jvm肯定解决了这个问题,openjdk源码在AccessController.doPrivileged

    学名叫做沙箱安全机制,主要作用是:保护核心类,防止打破双亲委派机制,防篡改,如果重名的话就报异常,这里的重名指包名加类名都重复。

    demo:

    package java.lang;

    public class Integer {

    public static void main(String[] args) {

    System.out.println("1");

    }

    }

    运行报错:

    错误: 在类 java.lang.Integer 中找不到 main 方法, 请将 main 方法定义为:

    public static void main(String[] args)

    否则 JavaFX 应用程序类必须扩展javafx.application.Application

    标签:委派,String,示例,public,双亲,class,加载

    来源: https://blog.csdn.net/qq_39404258/article/details/112065471

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,243
精华内容 1,297
热门标签
关键字:

双亲委派机制