`
天使的左手
  • 浏览: 55451 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ClassLoader

    博客分类:
  • java
阅读更多
public class ClassLoaderTest
{
    /**
       Java的类加载器采用了一种父委托机制来加载需要的类.每个ClassLoader都关联一个父ClassLoader,
       除了BootstrapClassLoader(启动类加载器)外.Java默认实现了三个类加载器:
       BootstrapClassLoader(最顶层的类加载器),ExtClassLoader(扩展类加载器),AppClassLoader(系统类加载器),
       其中ExtClassLoader的父加载器是BootstrapClassLoader,而AppClassLoader的父加载器是
       ExtClassLoader.
       BootstrapClassLoader默认从sun.boot.class.path环境变量设置的路径加载类文件,
       ExtClassLoader默认从java.ext.dirs环境变量设置的路径加载类文件,AppClassLoader默认是从
       java.class.path环境变量设置的路径加载类文件.
       当一个类加载器试图加载一个类时,会先在自己的本地缓存(表达不是很恰当)中查找,如果之前已经加载过
       这个类,就直接返回.如果没找到就委托给父加载器去加载,没找到继续往上查找,
       也就是说一开始让最高层的父加载器加载这个类,父加载器加载成功,直接返回,并将这个类对象缓存起来,
       如果加载不了,就让第二层父加载器加载,直到找到自己,如果自己也不能加载这个类,抛出ClassNotFoundException
       
        因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
        考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态
        替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,
        因为String已经在启动时就被引导类加载器(BootstrapClassLoader)加载,
        所以用户自定义的ClassLoader永远也无法加载一个自己写的String,
        除非你改变JDK中ClassLoader搜索类的默认算法(重写loadClass方法)
       
       JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。
       只有两者同时满足的情况下,JVM才认为这两个class是相同的。
     */

    // 启动类加载器的类加载路径
    private static void getBootstrapClassPath2()
    {
        /**
         * 结果: file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/resources.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/rt.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/sunrsasign.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/jsse.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/jce.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/lib/charsets.jar
         * file:/C:/Program%20Files/Java/jdk1.6.0_17/jre/classes/
         */
        URL[] urls = Launcher.getBootstrapClassPath().getURLs();
        for (URL url : urls)
        {
            System.out.println(url);
            // 获取没有被转义的路径
            // System.out.println(url.toURI().getPath());
        }
    }

    // 启动类加载器的类加载路径
    private static void getBootstrapClassPath()
    {
        // 直接从环境变量获取启动类加载器的类加载路径
        /**
         * 结果: C:\Program Files\Java\jdk1.6.0_17\jre\lib\resources.jar
         * C:\Program Files\Java\jdk1.6.0_17\jre\lib\rt.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\lib\sunrsasign.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\lib\jsse.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\lib\jce.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\lib\charsets.jar C:\Program
         * Files\Java\jdk1.6.0_17\jre\classes 自己添加的,JDK默认不包含这个目录
         */

        // 在VM参数中加入选项:-Xbootclasspath/a:c:\cl.jar
        // 表示在原有的启动类加载器的类加载路径后面加上一个c:\cl.jar包
        // 选项-verbose 可以输出虚拟机启动过程中类被加载的详细信息
        String bootstrapClassPath = System.getProperty("sun.boot.class.path");
        String[] parts = bootstrapClassPath.split(";");
        for (String part : parts)
            System.out.println(part);
    }

    private static void classLoaderHierarchy()
    {
        /**
         * 结果: Current class loader: sun.misc.Launcher$AppClassLoader@47858e
         * Parent class loader: sun.misc.Launcher$ExtClassLoader@19134f4 Parent
         * class loader: null
         */
        ClassLoader loader = ClassLoaderTest.class.getClassLoader();
        System.out.println("Current class loader: " + loader);
        while (loader != null)
        {
            loader = loader.getParent();
            System.out.println("Parent class loader: " + loader);
        }
    }
}
public class URLClassLoader extends ClassLoader
{/**
     * 自定义类加载器
     */
    public static void main(String[] args) throws Exception
    {
        String baseURL = "http://localhost:8080/rat/classes";
        URLClassLoader ucl = new URLClassLoader(baseURL, null);
        Class<?> clazz = ucl.loadClass("com.classloader.SimpleObj");
        System.out.println("class: " + clazz);
        //父加载器找不到SimpleObj,所以最终由我们自己定义的类加载器加载
        //class loader: com.classloader.URLClassLoader@1034bb5
        System.out.println("class loader: " + clazz.getClassLoader());

        //SimpleObj默认由AppClassLoader加载,此时SimpleObj存在classpath中
        //所以定义类加载器(最终执行类加载的那个类加载器)为AppClassLoader
        SimpleObj obj = new SimpleObj();
        System.out.println("class: " + obj.getClass());
        //class loader: sun.misc.Launcher$AppClassLoader@47858e
        System.out.println("class loader: " + obj.getClass().getClassLoader());

        //target的类文件是由我们自定义类加载器加载的
        //obj的类文件是由系统类加载器加载的 是两个不同的类型
        Object target = clazz.newInstance();
        System.out.println("target: " + target);
        Method m = clazz.getMethod("setObj", Object.class);
        System.out.println(m);
        //所以此时利用反射调用target对象的setObj会出现类型转异常
        //Caused by: java.lang.ClassCastException: com.classloader.SimpleObj 
        //cannot be cast to com.classloader.SimpleObj
        //at com.classloader.SimpleObj.setObj(SimpleObj.java:34)
        m.invoke(target, obj);
    }

    private String baseURL;

    public URLClassLoader(String baseURL)
    {
        this(baseURL, getSystemClassLoader());
    }

    public URLClassLoader(String baseURL, ClassLoader parent)
    {
        super(parent);
        this.baseURL = baseURL;
    }

    //loadClass中定义了类加载的规则,如果遍历完所有的父加载器后,都不能完成类的加载,
    //就会调用findClass方法去加载所要的类,所以实现自己的类加载器时,只要覆写findClass即可
    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException
    {
        byte[] data = getClassData(name);
        if (data == null)
            throw new ClassNotFoundException(name);
        return defineClass(name, data, 0, data.length);
    }

    private byte[] getClassData(String name)
    {
        InputStream in = null;
        try
        {
            URL url = new URL(className2FilePath(name));
            in = url.openStream();
            byte[] buf = new byte[4 * 1024];
            int len = 0;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            while (-1 != (len = in.read(buf)))
                baos.write(buf, 0, len);

            return baos.toByteArray();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (in != null)
            {
                try
                {
                    in.close();
                }
                catch (IOException e)
                {
                }
            }
        }
        return null;
    }

    private String className2FilePath(String name)
    {
        return baseURL + "/" + name.replace(".", "/") + ".class";
    }
}
分享到:
评论

相关推荐

    ClassLoader运行机制 自己写的

    在Java虚拟机(JVM)中,类加载器(ClassLoader)是至关重要的组成部分,它负责查找和加载类的字节码文件。理解ClassLoader的工作机制对于深入掌握Java应用程序的运行至关重要。这里我们将详细讨论ClassLoader的运行...

    深入理解ClassLoader工作机制.docx

    《深入理解ClassLoader工作机制》 Java虚拟机(JVM)中的ClassLoader是负责加载类到内存中的核心组件。它不仅承担着将字节码转换为可执行对象的重任,还参与了类生命周期的各个阶段,包括加载、验证、准备、解析、...

    自定义classloader的使用

    在Java中,Classloader是加载类的关键组件,它负责查找、加载和初始化字节码文件。自定义Classloader允许开发者根据特定需求定制类的加载逻辑,例如加密类文件、隔离不同版本的库或者动态加载代码。本文将深入探讨...

    ClassLoader小例子

    在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。本示例"ClassLoader小例子"将深入探讨这个概念,并通过一个具体的程序来演示其工作原理。下面我们...

    classloader

    Java ClassLoader是Java运行时系统的关键但经常被忽视的组件,负责在运行时查找和加载类文件。通过创建自定义ClassLoader,你可以定制JVM,使类文件的引入方式完全重新定义,这提供了很多实用和有趣的可能。这篇教程...

    java ClassLoader机制及其在OSGi中的应用

    Java ClassLoader机制是Java虚拟机(JVM)中一个至关重要的组成部分,它的主要任务是将类的.class文件加载到JVM中,使得程序能够运行。ClassLoader不仅负责类的加载,还涉及类的验证、初始化等一系列过程。理解...

    classloader 加密解密应用程序 ,反编译class

    在Java编程语言中,`ClassLoader`是一个至关重要的组件,它负责加载类到JVM(Java虚拟机)中。本文将深入探讨`ClassLoader`的工作原理、加密解密应用程序以及如何防止类被反编译。 首先,让我们理解`ClassLoader`的...

    Java ClassLoader定制实例

    在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...

    lassLoader的关系以及如何防止ClassLoader内存泄漏

    在Java世界中,类加载器(ClassLoader)是关键的组件之一,它负责将类的字节码文件(.class)从文件系统或网络中加载到Java虚拟机(JVM)中,使得程序能够运行。本篇文章将深入探讨ClassLoader的关系网络以及如何...

    ClassLoader 详解.doc

    《ClassLoader详解》 Java应用程序的运行离不开类的加载,而ClassLoader正是这个过程的关键角色。它负责将类的字节码加载到Java虚拟机(JVM)中并转换为可执行的Java对象。深入理解ClassLoader的工作原理对于优化...

    理解Java ClassLoader机制

    Java ClassLoader机制是Java运行时环境中的核心组件之一,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。理解ClassLoader的工作原理对于优化应用性能、处理类加载问题以及实现自定义加载器至关重要。 首先...

    ClassLoader类加载机制和原理详解

    在Java编程语言中,ClassLoader是核心组件之一,它负责加载类到JVM(Java虚拟机)中执行。本文将深入探讨ClassLoader的工作原理和类加载机制,帮助开发者理解这个至关重要的概念。 1. 类加载机制概述 Java的类加载...

    ClassLoader的 一些测试

    在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中执行。这篇测试主要探讨了ClassLoader的工作原理及其在实际应用中的使用。通过阅读给出的博文链接,我们可以深入理解...

    java classloader classpath 张孝祥

    ### Java ClassLoader与ClassPath详解 #### 一、概述 在Java编程中,类加载机制是十分关键的一个环节。类加载器(`ClassLoader`)负责将编译后的`.class`文件加载到Java虚拟机(JVM)中执行,而类路径(`ClassPath...

    classloader体系结构(含hotswap)

    Java的类加载器(ClassLoader)体系结构是JVM(Java虚拟机)中至关重要的一部分,它负责将类的字节码转换为运行时的类实例。本文将深入探讨启动类加载器、扩展类加载器、系统类加载器以及用户自定义类加载器,同时还...

    破解java加密的ClassLoader.java,在classloader植入破解代码

    破解java加密的ClassLoader.java,在classloader植入破解代码

Global site tag (gtag.js) - Google Analytics