栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

类加载器和双亲委派

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

类加载器和双亲委派

public class T1_ClassLoaderLevel {
    public static void main( String[] args) {
        System.out.println(String.class.getClassLoader() );
        System.out.println(sun.awt.HKSCS.class.getClassLoader() );
        System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
        System.out.println(T1_ClassLoaderLevel.class.getClassLoader());
        
        System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader() .getClass().getClassLoader());
        System.out .println(T1_ClassLoaderLevel.class.getClassLoader ().getClass().getClassLoader());
    }
}

运行结果

null
null
sun.misc.Launcher$ExtClassLoader@6d6f6e28
sun.misc.Launcher$AppClassLoader@18b4aac2
null
null


父加载器不是类加载器的加载器 也不是类加载器的父类加载器

public class T2_ParentAndChild {
public static void main( String[] args){
    System.out.println(T2_ParentAndChild.class.getClassLoader());
    System.out.println(T2_ParentAndChild.class.getClassLoader() .getClass().getClassLoader());
    System.out.println(T2_ParentAndChild.class.getClassLoader( ).getParent());
    System.out.println(T2_ParentAndChild.class.getClassLoader() .getParent() .getParent());

    System.out.println(T2_ParentAndChild.class.getClassLoader ( ) . getParent().getParent ( ) .getParent());
    }
}

运行结果

sun.misc.Launcher$AppClassLoader@18b4aac2
null
sun.misc.Launcher$ExtClassLoader@4554617c
null
Exception in thread "main" java.lang.NullPointerException
	at com.jsxl.jvm.classload.T2_ParentAndChild.main(T2_ParentAndChild.java:10)

Launcher$AppClassLoader(代表AppClassLoader是Launcher下面的内部类,查源码自行了解)

public class T3_classLoaderScope {
    public static void main( String[] args) {
        String pathBoot = System.getProperty( "sun.boot.class.path");
        System.out.println(pathBoot.replaceAll(  ";",System.lineSeparator()));
        System.out.println ("--------------------");
        String pathExt = System.getProperty( "java.ext.dirs");
        System.out.println(pathExt.replaceAll(  ";",System.lineSeparator()));
        System.out.println ( "--------------------");
        String pathApp = System.getProperty("java.class.path");
        System.out.println(pathApp.replaceAll(  ";",System.lineSeparator()));
    }
}

运行结果

D:javajava8jdk1.8.0_91jrelibresources.jar
D:javajava8jdk1.8.0_91jrelibrt.jar
D:javajava8jdk1.8.0_91jrelibsunrsasign.jar
D:javajava8jdk1.8.0_91jrelibjsse.jar
D:javajava8jdk1.8.0_91jrelibjce.jar
D:javajava8jdk1.8.0_91jrelibcharsets.jar
D:javajava8jdk1.8.0_91jrelibjfr.jar
D:javajava8jdk1.8.0_91jreclasses
--------------------
D:javajava8jdk1.8.0_91jrelibext
C:WindowsSunJavalibext
--------------------
D:javajava8jdk1.8.0_91jrelibcharsets.jar
D:javajava8jdk1.8.0_91jrelibdeploy.jar
D:javajava8jdk1.8.0_91jrelibextaccess-bridge-64.jar
D:javajava8jdk1.8.0_91jrelibextcldrdata.jar
D:javajava8jdk1.8.0_91jrelibextdnsns.jar
D:javajava8jdk1.8.0_91jrelibextjaccess.jar
D:javajava8jdk1.8.0_91jrelibextjfxrt.jar
D:javajava8jdk1.8.0_91jrelibextlocaledata.jar
D:javajava8jdk1.8.0_91jrelibextnashorn.jar
D:javajava8jdk1.8.0_91jrelibextsunec.jar
D:javajava8jdk1.8.0_91jrelibextsunjce_provider.jar
D:javajava8jdk1.8.0_91jrelibextsunmscapi.jar
D:javajava8jdk1.8.0_91jrelibextsunpkcs11.jar
D:javajava8jdk1.8.0_91jrelibextzipfs.jar
D:javajava8jdk1.8.0_91jrelibjavaws.jar
D:javajava8jdk1.8.0_91jrelibjce.jar
D:javajava8jdk1.8.0_91jrelibjfr.jar
D:javajava8jdk1.8.0_91jrelibjfxswt.jar
D:javajava8jdk1.8.0_91jrelibjsse.jar
D:javajava8jdk1.8.0_91jrelibmanagement-agent.jar
D:javajava8jdk1.8.0_91jrelibplugin.jar
D:javajava8jdk1.8.0_91jrelibresources.jar
D:javajava8jdk1.8.0_91jrelibrt.jar
D:githubJVMtargetclasses
D:toolsideaIntelliJ IDEA 2018.3.6libidea_rt.jar
自定义类加载器

继承ClassLoader
重写模板方法findClass调用defineClass

自定义类加载器加载自加密的class

  • 防止反编译
  • 防止篡改
public class T4_LoadClassByHand {
    public static void main(String[] args) throws ClassNotFoundException {
        Class clazz = T4_LoadClassByHand.class.getClassLoader().loadClass("com.jsxl.jvm.classload.T2_ParentAndChild");
        System.out.println(clazz.getName());

        //利用类加载器加载资源
//        T4_LoadClassByHand.class.getClassLoader ( ). getResourceAsStream("");
    }
}
loadClass源码
   protected Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }

ClassLoader源码解析

findClass
如果是AppClassLoader首先会执行URLClassLoader的findClass方法
思考这是一个什么设计模式?

public class T5_DefineClassLoad extends ClassLoader {
    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        File f = new File("c:/test/", name.replaceAll(" .", "/").concat(".class"));
        try {
            FileInputStream fis = new FileInputStream(f);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b = 0;

            while ((b = fis.read()) != 0) {
                baos.write(b);
            }
            byte[] bytes = baos.toByteArray();
            baos.close();
            fis.close();//可以写的更加严谨

            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.findClass(name); //throws ClassNotFoundException
    }

    public static void main(String[] args) throws Exception {
        ClassLoader l = new T5_DefineClassLoad();
        Class clazz = l.loadClass("com.jsxl.jvm.classload.Hello");
        Hello h = (Hello) clazz.newInstance();
        h.m();
        System.out.println(l.getClass().getClassLoader());
        System.out.println(l.getParent());
    }
}
public class Hello {
    public void m(){
        System.out.println("hello word");
    }
}

运行结果

hello word
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2

加密

package com.jsxl.jvm.classload;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class T6_MSBClassLoaderwithEncription extends ClassLoader {

    public static int seed = 0B10110110;
    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        File f = new File("D:/test/", name.replaceAll("\.", "/").concat(".lhtclass"));
        try {
            FileInputStream fis = new FileInputStream(f);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b = 0;

            while ((b = fis.read()) != 0) {
                baos.write(b);
            }
            byte[] bytes = baos.toByteArray();
            baos.close();
            fis.close();//可以写的更加严谨
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.findClass(name); //throws ClassNotFoundException
    }

    public static void main(String[] args) throws Exception {
        encFile ("com.jsxl.jvm.classload.Hello" ) ;
        ClassLoader l = new T6_MSBClassLoaderwithEncription();
        Class clazz = l.loadClass("com.jsxl.jvm.classload.Hello");
        Hello h = (Hello)clazz.newInstance();
        h.m();
        System.out.println(l.getClass().getClassLoader( ) );
        System.out.println(l.getParent());
    }


        private static void encFile(String name) throws Exception {
            File f = new File( "D:/test/",name.replace( "." ,"/" ).concat(".class"));
            FileInputStream fis = new FileInputStream(f);
            FileOutputStream fos = new FileOutputStream(new File("D:/test/",name.replaceAll(  "\.","/" ).concat(".lhtclass")));
            int b = 0;
            while((b = fis.read()) != -1) {
                fos.write(b^seed);
            }
            fis.close();
            fos.close();
        }
}
解释器(java是混合模式)

解释器
bytecode intepreter

JIT
Just ln-Time compiler

混合模式

  • 混合使用解释器+热点代码编译
  • 起始阶段采用解释执行
  • 热点代码检测
  • 多次被调用的方法(方法计数器:监测方法执行频率)
  • 多次被调用的循环(循环计数器:检测循环执行频率)
  • 进行编译

Xmixed 默认为混合模式
开始解释执行,启动速度较快对热点代码实行检测和编译

public class T7_WayToRun {
    public static void main(String[] args) {
        for (int i = 0; i < 100000; i++) m();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) m();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
    public static void m() {
        for (long i = 0; i < 100000L; i++) {
            long j=i%3;}
    }
}
输出:2541

Xint使用编译模式,启动很快执行稍慢

Xcomp使用纯编译模式,执行很快,启动很慢

lazyloading
  • 严格讲应该叫lazylnitializing
  • JVM规范并没有规定何时加载
  • 但是严格规定了什么时候必须初始化
    • new getstatic putstatic invokestatic指令,访问final变量除外
    • java.lang.reflect对类进行反射调用时
    • 初始化子类的时候,父类首先初始化-虚拟机启动时,被执行的主类必须初始化
    • 动态语言支持java.lang.invoke.MethodHandle解析的结果为
    • REFgetstatic REF putstatic REF_invokestatic的方法句柄时,该类必须初始化
public class Tc08_LazyLoading { //严格讲应该叫lazyinitialzing,因为java虚拟机规范并没有严格规定什么时候必须Lodding
    public static void main(String[] args) throws Exception {
        P p;
//        X x = new X( );
//        System.out.println(P.i);
//        System.out.println(P.j);
//        Class.forName("com.jsxl.jvm.classload.Tc08_LazyLoading$P");
    }

    public static class P {
        final static int i = 8;
        static int j = 9;

        static {
            System.out.println("P");
        }
    }

    public static class X extends P {
        static {
            System.out.println("x");
        }
    }
public class T010_Parent {
    private static T5_DefineClassLoad parent = new T5_DefineClassLoad();
        private static class MyLoader extends ClassLoader {
            public MyLoader(){
            super(parent);
        }
    }
}
public class T02_ClassLoaderLevel {
    public static void main( String[] args) {
        System.out.println( String.class.getClassLoader());
        System.out.println(sun.awt.HKSCS.class.getClassLoader() );
        System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
        System.out.println(T02_ClassLoaderLevel.class.getClassLoader());
        System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
        System.out.println(T02_ClassLoaderLevel.class.getClassLoader().getParent());
        System.out.println(new T5_DefineClassLoad().getParent());
        System.out.println(ClassLoader.getSystemClassLoader());
    }
}
public class To11_classReloading {
    public static void main(String[] args) throws Exception {
        T5_DefineClassLoad ClassLoader = new T5_DefineClassLoad();
        Class clazz = ClassLoader.loadClass("com.jsxl.jvm.classload.Hello");
        ClassLoader = null;
        System.out.println(clazz.hashCode());
        ClassLoader = null;
        ClassLoader = new T5_DefineClassLoad();
        Class clazz1 = ClassLoader.loadClass("com.jsxl.jvm.classload.Hello");
        System.out.println(clazz1.hashCode());
        System.out.println(clazz == clazz1);
    }
}

打破

public class To12_classReloading2 {
    private static class MyLoader extends ClassLoader {
        @Override
        public Class loadClass(String name) throws ClassNotFoundException {
            File f = new File("D:/github/JVM/" + name.replaceAll("\.", "/").concat(".class"));
            if (!f.exists()) return super.loadClass(name);
            try {
                InputStream is = new FileInputStream(f);
                byte[] b = new byte[is.available()];
                is.read(b);
                return defineClass(name, b, 0, b.length);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return super.loadClass(name);
        }
    }

    public static void main(String[] args) throws Exception {
        MyLoader m = new MyLoader();
        Class clazz = m.loadClass("com.jsxl.jvm.classload.Hello");
        m = new MyLoader();
        Class clazzNew = m.loadClass("com.jsxl.jvm.classload.Hello");
        System.out.println(clazz == clazzNew);
    }
}

JVM类加载过程

  • 加载: Loading
  • 连接: linking
  • 验证: Verification(验证文件是否符合JVM规范)
  • 准备: Preparation(静态成员变量赋默认值)
  • 解析: Resolution(将类、方法、属性等符号引用解析为真接引用 ,常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用)
  • 初始化:Initializing(调用类初始化代码)
  • 卸载:Unloading
  • 使用:Using
  • 初始化:
public class T001_classLoadingProcedure {
    public static void main(String[] args) {
        System.out.println(T.count);
    }
}

class T {
    public static int count = 2;    // 0
    public static T t = new T();    // null
    // private int m = 8;

//    public static T t = new T();    //null
//    public static int count = 2;    // 0

    private T() {
        count++;
        System.out.println("—-" + count);
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/672434.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号