zoukankan      html  css  js  c++  java
  • Java-JVM 自定义类加载器

    一、sun.misc.Launcher (ExtClassLoader 与 AppClassLoader 的创建)

    public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }
    
        try {
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }
    
        Thread.currentThread().setContextClassLoader(this.loader);
        String var2 = System.getProperty("java.security.manager");
        if (var2 != null) {
            SecurityManager var3 = null;
            if (!"".equals(var2) && !"default".equals(var2)) {
                try {
                    var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
                } catch (IllegalAccessException var5) {
                } catch (InstantiationException var6) {
                } catch (ClassNotFoundException var7) {
                } catch (ClassCastException var8) {
                }
            } else {
                var3 = new SecurityManager();
            }
    
            if (var3 == null) {
                throw new InternalError("Could not create SecurityManager: " + var2);
            }
            System.setSecurityManager(var3);
        }
    }
    View Code

    二、自定义类加载器(继承 ClassLoader 类,重写 findClass 方法,不推荐重写 loadClass 方法,会破坏委派机制)

    测试加载类,使用 javac 把 .java 文件编译成 .class 文件

    package com;
    
    public class Hello {
        static {
            System.out.println("Hello !");
        }
        
        public void sayHi(String name){
            System.out.println("Hello !" + name);
        }
    }

    类加载器,注意要加载类的路径名与包名

    package com;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.lang.reflect.Method;
    
    public class ClassLoaderTest extends ClassLoader {
    
        private final static String filePathSuffix = ".class";
        private String filePathPrefix;
    
        public ClassLoaderTest(String filePathPrefix) {
            this.filePathPrefix = filePathPrefix;
        }
    
        @Override
        protected Class<?> findClass(String name) {
            String fileName = name.split("\.")[name.split("\.").length - 1];
            byte[] bytes = loadClassData(filePathPrefix + fileName + filePathSuffix);
            return defineClass(name, bytes, 0, bytes.length);
        }
    
        private byte[] loadClassData(String filePath) {
            InputStream in = null;
            ByteArrayOutputStream out = null;
            try {
                in = new FileInputStream(new File(filePath));
                out = new ByteArrayOutputStream();
                int i = 0;
                while ((i = in.read()) != -1) {
                    out.write(i);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    out.close();
                    in.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return out.toByteArray();
        }
    
        public static void main(String[] args) throws Exception {
            ClassLoaderTest clt = new ClassLoaderTest("D:/");
            Class c = clt.loadClass("com.Hello");
            System.out.println(c.getClassLoader());
            System.out.println(c.getClassLoader().getParent());
            System.out.println(c.getClassLoader().getParent().getParent());
            System.out.println(c.getClassLoader().getParent().getParent().getParent());
            Method sayHi = c.getMethod("sayHi", String.class);
            // 无参实例化
            Object o = c.newInstance();
            // 调用方法
            sayHi.invoke(o, "zhangsan");
        }
    }

    三、Class.forName() 和 ClassLoader.loadClass()

    调用了 forName0,第二个参数为 true,默认会初始化,可使用其重载方法指定为 false

    @CallerSensitive
    public static Class<?> forName(String className) throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

    调用了 loadClass 的重载方法,默认不会链接,就不会初始化了

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

    以上面的 Hello 类为例,在 com 包下新建同样的文件,命名为 Hello1

    public static void main(String[] args) throws Exception {
        // 加载,链接,初始化
        Class.forName("com.Hello1");
        System.out.println("==========================================");
        // 加载,链接
        Class.forName("com.Hello1", false,ClassLoader.getSystemClassLoader());
        System.out.println("==========================================");
        // 加载
        ClassLoader.getSystemClassLoader().loadClass("com.Hello1");
    }

    四、线程上下文类加载器(ThreadContextClassLoader)

    https://mp.weixin.qq.com/s/4FJbRLUcg8FmOqP1uz3f2A

    java.lang.Thread 中的方法 getContextClassLoader() 和 setContextClassLoader(ClassLoader cl) 用来获取和设置线程的上下文类加载器。

    如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。

    Java 应用运行的初始线程的上下文类加载器是系统类加载器。

    Thread thread = new Thread(()->{
        try {
            Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass("com.Hello");
            System.out.println(aClass.getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    });
    thread.setContextClassLoader(new ClassLoaderTest("D:/"));
    thread.start();
    
    Thread.sleep(1000);
    
    thread = new Thread(()->{
        try {
            Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass("com.Hello1");
            System.out.println(aClass.getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    });
    thread.start();


    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.3.2

    https://www.cnblogs.com/editice/p/5420712.html

  • 相关阅读:
    查询sql数据库中表占用的空间大小
    清理sql2012数据库日志
    完美解决distinct中使用多个字段的方法
    【Visual Studio 扩展工具】如何在ComponentOneFlexGrid树中显示RadioButton
    关于ComponentOne For WinForm 的全新控件 – DataFilter数据切片器(Beta)
    “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
    【Visual Studio 扩展工具】使用ComponentOne中的GroupDefinition和SortDefinition属性保存和还原布局
    【Visual Studio 扩展工具】使用 ComponentOne迷你图控件,进行可视化数据趋势分析
    ComponentOne 产品经理:为什么要从C1Report迁移到FlexReport
    ActiveReports 大数据分析报告:贸易争端与中国企业数字化转型
  • 原文地址:https://www.cnblogs.com/jhxxb/p/10921945.html
Copyright © 2011-2022 走看看