美文网首页
ClassLoader实战二、ClassLoader双亲委派模型

ClassLoader实战二、ClassLoader双亲委派模型

作者: 编程界的小学生 | 来源:发表于2017-08-28 16:56 被阅读77次

    1、双亲委派模型以及类加载机制前几篇文章都介绍过了,不懂的去看!!!此篇文章直接用用代码来证明是存在双亲委派的。

    2、类加载器双亲委派图

    Paste_Image.png

    自顶向下去加载类,双亲委派的目的就是为了防止重复加载!

    3、实战准备
    需要在D盘下的tmp文件夹下建立如下的目录

    Paste_Image.png Paste_Image.png Paste_Image.png Paste_Image.png

    a/Demo.java

    package com.dn;
    public class Demo {
    
        public Demo() {
            System.out.println("loader1 init....." + this.getClass().getClassLoader());
        }
    }
    

    b/Demo.java

    package com.dn;
    public class Demo {
    
        public Demo() {
            System.out.println("loader2 init....." + this.getClass().getClassLoader());
        }
    }
    

    c/Demo.java

    package com.dn;
    public class Demo {
    
        public Demo() {
            System.out.println("loader3 init....." + this.getClass().getClassLoader());
        }
    }
    

    4、自定义类加载器

    package jvm.dongnao.demo1;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class MyClassLoader extends ClassLoader {
    
        //类加载器名称
        private String name;
        //类加载路径
        private String path;
        
        public MyClassLoader(String name, String path) {
            super(); //默认的父类加载器
            this.name = name;
            this.path = path;
        }
        
        public MyClassLoader(ClassLoader parent, String name, String path) {
            super(parent); //父类加载器
            this.name = name;
            this.path = path;
        }
        
        /**
         * 获取当前指定路径下的类
         */
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] b = readFileToByteArray(name);
            return this.defineClass(name, b, 0, b.length);
        }
    
        /**
         * 将包名转换成全路径名,比如
         * 
         * temp.a.com.dn.Demo -> D:/temp/a/com/dn/Demo.class
         * 
         * @param name
         * @return
         */
        private byte[] readFileToByteArray(String name) {
            InputStream is = null;
            byte[] rtnData = null;
            //转换
            name = name.replaceAll("\\.", "/");
            //拼接
            String filePath = this.path + name + ".class";
            File file = new File(filePath);
            
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            
            try {
                is = new FileInputStream(file);
                int tmp = 0;
                while((tmp = is.read()) != -1) {
                    os.write(tmp);
                }
                
                rtnData = os.toByteArray();
                
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if(null != is) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(null != os) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return rtnData;
        }
    }
    

    5、main方法

    package jvm.dongnao.demo1;
    
    public class Test1 {
        
        public static void main(String[] args) throws Exception {
            //默认为AppClassLoader
            MyClassLoader loader1 = new MyClassLoader("loader1", "D:/tmp/a/");
            
            //父类加载器指定为loader1
            MyClassLoader loader2 = new MyClassLoader(loader1, "loader2", "D:/tmp/b/");
            
            //父类加载器传null,代表父类是bootstrapClassLoader
            MyClassLoader loader3 = new MyClassLoader(null, "loader3", "D:/tmp/c/");
            
            Class c = loader1.loadClass("com.dn.Demo"); //Demo.class,这里是全路径名称,必须带包名
            
            c.newInstance(); //实例化
        }
    }
    

    6、运行结果
    6.1、loader1

    Class c = loader1.loadClass("com.dn.Demo");
    
    loader1 init.....jvm.dongnao.demo1.MyClassLoader@5c647e05
    

    6.2、loader2

    Class c = loader2.loadClass("com.dn.Demo");
    
    loader2 init.....jvm.dongnao.demo1.MyClassLoader@5c647e05
    

    6.2、loader3

    Class c = loader3.loadClass("com.dn.Demo");
    
    loader3 init.....jvm.dongnao.demo1.MyClassLoader@6d06d69c
    

    可以发现loader1和loader2的类加载器是同一个,这就验证了loader2选取的类加载器并不是自己的,而是父类的类加载器,因为

    new MyClassLoader(loader1, "loader2", "D:/tmp/b/");
    

    第一个参数是传递父类类加载器,将loader1传进去了,所以去loader1加载Demo.class,loader2不会重复加载,双亲委派模型也正是为了防止重复加载而生的。

    若有兴趣,欢迎来加入群,【Java初学者学习交流群】:458430385,此群有Java开发人员、UI设计人员和前端工程师。有问必答,共同探讨学习,一起进步!
    欢迎关注我的微信公众号【Java码农社区】,会定时推送各种干货:


    qrcode_for_gh_577b64e73701_258.jpg

    相关文章

      网友评论

          本文标题:ClassLoader实战二、ClassLoader双亲委派模型

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