zoukankan      html  css  js  c++  java
  • JVM 自定义类加载器在复杂类情况下的运行分析

    一、自定义类加载器在复杂类情况下的运行分析

    1、使用之前创建的类加载器

    public class MyTest16  extends  ClassLoader{
    
        private String className;
    
        //目录
         private String path;
    
        private final String fileExtension = ".class";
    
        public MyTest16(String classLoadName){
            super(); //将系统类加载器当做该类加载器的父加载器
            this.className = classLoadName;
        }
    
        public MyTest16(ClassLoader parent, String classLoadName){
            super(parent); //显示指定该类加载器的父加载器器
            this.className = classLoadName;
        }
    
        public void setPath(String path) {
            this.path = path;
        }
    
        @Override
        public String toString() {
            return "[" + this.className + "]";
        }
    
        @Override
        protected Class<?> findClass(String clasName) throws ClassNotFoundException {
            System.out.println("findClass invoked:" + clasName);
            System.out.println("class loader name: " + this.className);
            byte[] data = this.loadClassData(clasName);
            return  this.defineClass(clasName,data, 0, data.length);
        }
    
        private byte[] loadClassData(String className){
            InputStream is = null;
            byte[] data = null;
            ByteArrayOutputStream baos = null;
    
            try{
                className = className.replace(".","//");
                //System.out.println("className:" +this.className);
                is = new FileInputStream(new File(this.path + className + this.fileExtension));
                baos = new ByteArrayOutputStream();
                int ch = 0;
                while ( -1 != (ch = is.read())){
                    baos.write(ch);
                }
                data = baos.toByteArray();
    
            }catch (Exception ex){
                ex.printStackTrace();
            }finally {
                try {
                    is.close();
                    baos.close();
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }
    
            return  data;
    
        }
    
       
    
    
    }
    

      

    2、创建MyCat类

    public class MyCat {
        public MyCat(){
            System.out.println("MyCat is loaded by:" + this.getClass().getClassLoader());
        }
    }
    

      

    3、创建MySample类

    public class MySample {
    
        public MySample(){
            System.out.println("MySample is loaded by:" + this.getClass().getClassLoader());
            new MyCat();
    
        }
    }
    

      

    4、创建测试类

    public class MyTest17 {
        public static void main(String[] args)  throws  Exception{
            MyTest16 loader1 = new MyTest16("loader1");
    
            Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MySample");
    
            System.out.println("class:" + clazz.hashCode());
    
            //如果注释掉改行,那么并不会实例化MySample对象,即MySample构造方法不会被调用
            //因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加重MyCat Class
            Object object = clazz.newInstance();
    
    
    
        }
    }
    

      

    打印结果

    class:1735600054
    MySample is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
    MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
    

      

    增加-XX:+TraceClassLoading后的打印结果

     

    如果去掉Object object = clazz.newInstance();

    打印结果为

    说明:如果注释掉Object object = clazz.newInstance();该行,那么并不会实例化MySample对象,即MySample构造方法不会被调用

             因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加载MyCat Class。

             而且这个例子说明MyCat没有被预先加载

    二、对一的Code进行改造

    在一的基础上,新建一个测试类

    public class MyTest17_1 {
        public static void main(String[] args)  throws  Exception{
            MyTest16 loader1 = new MyTest16("loader1");
            loader1.setPath("D:/temp/");
            Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MySample");
    
            System.out.println("class:" + clazz.hashCode());
    
            //如果注释掉该行,那么并不会实例化MySample对象,即MySample构造方法不会被调用
            //因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加载MyCat Class
            Object object = clazz.newInstance();
    
    
    
        }
    }
    

      里面增加了一个方法loader1.setPath("D:/temp/");

    然后将MyCat.class 和MySample.class 剪切到D:/temp/目录下,如下面两图

    打印结果:

    findClass invoked:com.example.jvm.classloader.MySample
    class loader name: loader1
    class:2133927002
    MySample is loaded by:[loader1]
    findClass invoked:com.example.jvm.classloader.MyCat
    class loader name: loader1
    MyCat is loaded by:[loader1]
    

      

    三、类加载命名空间

    在二的基础上,MyCat.java 增加一行代码System.out.println("from MyCat:" + MySample.class);

    public class MyCat {
        public MyCat(){
            System.out.println("MyCat is loaded by:" + this.getClass().getClassLoader());
    
            System.out.println("from MyCat:" + MySample.class);
        }
    }
    

      然后重新build,打印结果如下:

    class:1735600054
    MySample is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
    MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
    from MyCat:class com.example.jvm.classloader.MySample
    

      

    现在将build路径下的classloader文件夹拷贝到D: empcomexamplejvmclassloader下,删除build路径下的MySample.class

    打印输出结果:

    findClass invoked:com.example.jvm.classloader.MySample
    class loader name: loader1
    class:2133927002
    MySample is loaded by:[loader1]
    MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
    Exception in thread "main" java.lang.NoClassDefFoundError: com/example/jvm/classloader/MySample
    	at com.example.jvm.classloader.MyCat.<init>(MyCat.java:10)
    	at com.example.jvm.classloader.MySample.<init>(MySample.java:10)
    	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    	at java.lang.Class.newInstance(Class.java:442)
    	at com.example.jvm.classloader.MyTest17_1.main(MyTest17_1.java:16)
    Caused by: java.lang.ClassNotFoundException: com.example.jvm.classloader.MySample
    	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    	... 8 more
    

      说明:MySample由自定义loader加载,MyCat由AppClassLoader。两个类是不同的loader加载,处于不同的命名空间。

         所以System.out.println("from MyCat:" + MySample.class); 抛出异常。 子加载器所加载的类能够访问父加载器所加载的类。反之,父加载器所加载的类无法访问子加载器所加载的类

      

  • 相关阅读:
    2020年捌月份生活随笔
    2020年柒月份生活随笔
    2020年陆月份生活随笔
    第二次:郑州银行杯|2019郑州国际马拉松
    第一次:海尔|2017年青岛马拉松
    专项测试技能和线上线下监控
    实用
    Oracle 数据库 有用的sql语句
    Qt demo
    springboot demo
  • 原文地址:https://www.cnblogs.com/linlf03/p/11027293.html
Copyright © 2011-2022 走看看