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

  • 相关阅读:
    Java生成二维码连接
    Spring boot 整合 Elasticsearch
    Windows下安装ElasticSearch
    springcloud zookeeper+gateway
    idea中Springcloud同时运行多个模块、微服务
    【转】为什么我的DIV块前总有空隙?
    【转载】通过JSFL让Flash Professional CS4或CS5拥有批量FLA导出SVG的功能
    jQuery Mobile中的页面加载与跳转机制
    关于Conversion to Dalvik format failed with error 1错误
    带权重的随机输出数组中的元素
  • 原文地址:https://www.cnblogs.com/jhxxb/p/10921945.html
Copyright © 2011-2022 走看看