zoukankan      html  css  js  c++  java
  • 自定义类加载器实现同时加载不同版本的相同类

    双亲委派原理


    引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等
    扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包
    应用程序类加载器:负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类
    自定义加载器:负责加载用户自定义路径下的类包

    为什么要设计双亲委派这种机制

    沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改
    避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性

    自定义类加载器实现

    public class MyClassLoaderTest {
        static class MyClassLoader extends ClassLoader {
            private String classPath;
    
            public MyClassLoader(String classPath) {
                this.classPath = classPath;
            }
    
            private byte[] loadByte(String name) throws Exception {
                name = name.replaceAll("\.", "/");
                FileInputStream fis = new FileInputStream(classPath + "/" + name
                        + ".class");
                int len = fis.available();
                byte[] data = new byte[len];
                fis.read(data);
                fis.close();
                return data;
            }
    
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                try {
                    byte[] data = loadByte(name);
                    //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
                    return defineClass(name, data, 0, data.length);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new ClassNotFoundException();
                }
            }
    
        }
    
        public static void main(String args[]) throws Exception {
            //初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
            MyClassLoader classLoader = new MyClassLoader("D:/test");
            //D盘创建 test/com/tuling/jvm 几级目录,将User类的复制类User1.class丢入该目录
            Class clazz = classLoader.loadClass("com.learn.jvm.User1");
            Object obj = clazz.newInstance();
            Method method = clazz.getDeclaredMethod("sout", null);
            method.invoke(obj, null);
            System.out.println(clazz.getClassLoader());
    
            System.out.println();
            MyClassLoader classLoader1 = new MyClassLoader("D:/test/test1");
            Class clazz1 = classLoader1.loadClass("com.learn.jvm.User1");
            Object obj1 = clazz1.newInstance();
            Method method1= clazz1.getDeclaredMethod("sout", null);
            method1.invoke(obj1, null);
            System.out.println(clazz1.getClassLoader());
        }
    }
    

    运行结果:

    =======自己的加载器加载类调用方法=======
    com.learn.jvm.MyClassLoaderTest$MyClassLoader@6d6f6e28
    
    =======另外一个版本USer1 自己的加载器加载类调用方法=======
    com.learn.jvm.MyClassLoaderTest$MyClassLoader@330bedb4
    

    如何打破双亲委派加载(TODO)

    参考:

    作者:薄荷加冰
    出处:https://www.cnblogs.com/huangjianping/
    版权:本文版权归作者和博客园共有
    转载:本文以学习、研究和分享为主,欢迎转载和各类爬虫,但必须在文章页面明显位置给出原文链接。 如果文中有不妥或者错误的地方还望您指出,以免误人子弟。如果您有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。
  • 相关阅读:
    【2019-12-20】做好人和己可以事半功倍
    【2019-12-11】人生信条再抄写
    【2019-12-10】人生信条抄写
    【2019-12-19】多跟自己讲讲道理
    【2019-12-18】要时刻警惕思维固化
    【2019-12-17】做人还是要回归朴实
    爬取美团
    总结day7 ---- 函数的内容 ,初识,返回值,进阶(一)
    day05 --class --home
    一期 自检:
  • 原文地址:https://www.cnblogs.com/huangjianping/p/14968403.html
Copyright © 2011-2022 走看看