`

Java基础恶补——ClassLoader

    博客分类:
  • Java
阅读更多

--------------------------------------------------------------------------------------------------------------

参考: http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html

--------------------------------------------------------------------------------------------------------------

 

要点

  • ClassLoader(类加载器) 基本概念:用来加载Java类到JVM中。Java源程序(.java文件)经编译器转换为Java字节代码(.class文件),类加载器负责读取Java字节代码并转换为java.lang.Class 类的一个实例。基本上所有的类加载器都是 java.lang.ClassLoader 类的一个实例。 
  • java.lang.ClassLoader 类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class 类的一个实例。除此之外,ClassLoader 还负责加载 Java 应用所需的资源,如图像文件和配置文件等。
  • ClassLoader 中与加载类相关的方法: 

 

方法 说明
getParent() 返回该类加载器的父类加载器。
loadClass(String name) 加载名称为 name 的类,返回的结果是 java.lang.Class 类的实例。
findClass(String name) 查找名称为 name 的类,返回的结果是 java.lang.Class 类的实例。
findLoadedClass(String name) 查找名称为 name 的已经被加载过的类,返回的结果是 java.lang.Class 类的实例。
defineClass(String name, byte[] b, int off, int len) 把字节数组 b 中的内容转换成 Java 类,返回的结果是 java.lang.Class 类的实例。这个方法被声明为 final 的。
resolveClass(Class<?> c) 链接指定的 Java 类。

 

  • java 类加载器分类:系统提供、开发人员编写。
  • 系统提供的加载器主要有:

    • 引导类加载器(bootstrap class loader): 它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader
    • 扩展类加载器(extensions class loader): 它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
    • 系统类加载器(system class loader): 它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的,可以通过 ClassLoader.getSystemClassLoader() 来获取它。

    开发人员可以通过继承 java.lang.ClassLoader 类的方式实现自己的类加载器。

     

     

     

     

    类加载器树状组织结构示意图如下:

     

  • 类加载器的代理模式 :代理模式是为了保证 Java 核心库的类型安全。所有 Java 应用都至少需要引用 java.lang.Object 类,也就是说在运行的时候,java.lang.Object 这个类需要被加载到 JVM 中。

    通过代理模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。 

    不同的类加载器为相同名称的类创建了额外的名称空间。相同名称的类可以并存在 JVM 中,只需要用不同的类加载器来加载它们即可。不同类加载器加载的类之间是不兼容的,这就相当于在 JVM 内部创建了一个个相互隔离的 Java 类空间。

  • 加载器类的过程 :真正完成类的加载工作是通过调用 defineClass 来实现的;而启动类的加载过程是通过调用 loadClass 来实现的。前者称为一个类的定义加载器(defining loader) ,后者称为初始加载器(initiating loader) 。在 JVM 判断两个类是否相同的时候,使用的是类的定义加载器。也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。两种类加载器的关联之处在于:一个类的定义加载器是它引用的其它类的初始加载器。如类 com.example.Outer 引用了类 com.example.Inner ,则由类 com.example.Outer 的定义加载器负责启动类 com.example.Inner 的加载过程。

    方法 loadClass() 抛出的是 java.lang.ClassNotFoundException 异常;方法 defineClass() 抛出的是 java.lang.NoClassDefFoundError 异常。 

    类加载器在成功加载某个类之后,会把得到的 java.lang.Class 类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。也就是说,对于一个类加载器实例来说,相同全名的类只加载一次,即 loadClass 方法不会被重复调用。

  • 线程上下文类加载器 :线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。

    java.lang.Thread 中的方法 getContextClassLoader() setContextClassLoader(ClassLoader cl) 用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl) 方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。

  • Class.forName : 是一个静态方法,同样可以用来加载类。

  • 类加载器和web容器:web容器的类加载器的实现方式与一般的 Java 应用有所不同。不同的 Web 容器的实现方式也会有所不同。以 Apache Tomcat 来说,每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是:Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。

  • 类加载器和OSGi: OSGi™ 是 Java 上的动态模块系统。 它为开发人员提供了面向服务和基于组件的运行环境,并提供标准的方式用来管理软件的生命周期。Eclipse 就是基于 OSGi 技术来构建的。

     

《Java核心技术,卷II:高级特性(原书第8版)》关于ClassLoader 的学习笔记



 

 

相关问题

1.  Q: 请实现一个类加载器。
   
A:  文件系统类加载器代码如下:

package com.example; 

public class Sample { 
    private Sample instance; 

    public void setSample(Object instance) { 
        this.instance = (Sample) instance; 
    } 
}

public void testClassIdentity() { 
    String classDataRootPath = "C:\\workspace\\Classloader\\classData"; 
    FileSystemClassLoader fscl1 = new FileSystemClassLoader(classDataRootPath); 
    FileSystemClassLoader fscl2 = new FileSystemClassLoader(classDataRootPath); 
    String className = "com.example.Sample"; 	
    try { 
        Class<?> class1 = fscl1.loadClass(className); 
        Object obj1 = class1.newInstance(); 
        Class<?> class2 = fscl2.loadClass(className); 
        Object obj2 = class2.newInstance(); 
        Method setSampleMethod = class1.getMethod("setSample", java.lang.Object.class); 
        setSampleMethod.invoke(obj1, obj2); 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } 
}

 

 一般来说,自己开发的类加载器只需要覆写 findClass(String name) 方法即可,,最好不要覆写 loadClass() 方法。

 

2.  Q: 运行以下代码会发生什么情况?  

public class FileSystemClassLoader extends ClassLoader { 

    private String rootDir; 

    public FileSystemClassLoader(String rootDir) { 
        this.rootDir = rootDir; 
    } 

    protected Class<?> findClass(String name) throws ClassNotFoundException { 
        byte[] classData = getClassData(name); 
        if (classData == null) { 
            throw new ClassNotFoundException(); 
        } 
        else { 
            return defineClass(name, classData, 0, classData.length); 
        } 
    } 

    private byte[] getClassData(String className) { 
        String path = classNameToPath(className); 
        try { 
            InputStream ins = new FileInputStream(path); 
            ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
            int bufferSize = 4096; 
            byte[] buffer = new byte[bufferSize]; 
            int bytesNumRead = 0; 
            while ((bytesNumRead = ins.read(buffer)) != -1) { 
                baos.write(buffer, 0, bytesNumRead); 
            } 
            return baos.toByteArray(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
        return null; 
    } 

    private String classNameToPath(String className) { 
        return rootDir + File.separatorChar 
                + className.replace('.', File.separatorChar) + ".class"; 
    } 
}

 

A:  运行时会抛出 java.lang.ClassCastException 异常。虽然两个对象 obj1 obj2 的类的名字相同,但是这两个类是由不同的类加载器实例来加载的,因此不被 JVM 认为是相同的。

       JVM是如何判定两个 Java 类是相同的:不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样,只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。

 

3.  Q: 请说出几种自定义类加载器的应用场合?  

 A: 1) Java 字节代码(.class文件)存放在服务器上,客户端通过网络的方式获取字节代码并执行。当有版本更新的时候,只需要替换掉服务器上保存的文件即可。

     2) 应用通过网络来传输 Java 类的字节代码,为了保证安全性,这些字节代码经过了加密处理。这个时候您就需要自己的类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出要在 JVM 中运行的类来。

 

  • 大小: 42.7 KB
  • 大小: 79.2 KB
  • 大小: 121.9 KB
分享到:
评论

相关推荐

    tomcat 类加载机制 —— ClassLoader

    《Tomcat类加载机制——ClassLoader详解》 在Java Web开发中,Tomcat作为最常用的Servlet容器,其类加载机制对于理解和优化应用性能至关重要。本文将深入探讨Tomcat的ClassLoader是如何工作的,以及它如何影响到...

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

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

    Java ClassLoader定制实例

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

    Java类加载器(ClassLoader)1

    Java类加载器(ClassLoader)是Java虚拟机(JVM)的核心组成部分,负责将类的字节码转换为可运行的Java对象。Java类加载器分为三种主要类型:引导类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ...

    2021Java大厂面试题——大厂真题之携程-Java高级.pdf

    ### 2021年Java大厂面试题详解——大厂真题之携程-Java高级 #### 一、JVM加载Class文件的原理机制 在深入理解Java虚拟机(JVM)如何加载Class文件之前,我们需要明确一点:Java的所有类都需要通过类加载器加载到JVM...

    java classloader

    Java ClassLoader是一个核心的Java运行时组件,负责加载类到Java虚拟机(JVM)中。它是Java平台的独特特性,因为它允许动态加载类,增强了软件的可扩展性和灵活性。这篇博文(虽然链接不可用)可能深入探讨了...

    java元数据——CLass类

    Java元数据——Class类 Java中的元数据Class类是一个基础的概念,它代理了这个类的类型信息、方法签名、属性等信息。每个类都有一个Class对象,它用来创建这个类的所有对象。每个对象的创建都依赖于Class对象的创建...

    java classloader classpath 张孝祥

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

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

    总结来说,Java ClassLoader机制是Java平台的基础,它使得程序能够动态地加载和管理类。而在OSGi这样的模块化环境中,ClassLoader机制得到了进一步的发展,实现了更加精细的类加载控制和更好的模块隔离。理解并掌握...

    Java ClassLoader Tutorial.zip

    一、Java ClassLoader 基础 1. 类加载过程:Java中的类加载分为三个阶段——加载、验证、准备、解析和初始化。ClassLoader主要参与的是加载阶段,它从磁盘、网络或其他数据源读取字节码文件,并将其转换为Class对象...

    java深度历险——王森

    关于JDK有两个问题是很容易一直困扰Java程序员的地方:一个是CLASSPATH的问题,其实从原理上来说,是要搞清楚JRE的ClassLoader是如何加载Class的;另一个问题是package和import问题,如何来寻找类的路径问题。把这两...

    理解Java ClassLoader机制

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

    Java ClassLoader原理

    动态类加载是Java虚拟机的基础机制之一,它为Java平台带来了许多独特的优势。例如,它使得应用程序能够在运行时从远程服务器下载和执行代码片段,从而极大地提高了系统的灵活性和响应速度。下面将详细介绍这些关键...

    Java之——类热加载

    Java之——类热加载 在Java编程中,类的加载是程序运行的重要环节。传统的Java应用程序在启动时,由JVM(Java虚拟机)通过类加载器将类加载到内存中,一旦加载完成,除非程序退出,否则这些类通常不会被重新加载。...

    Java ClassLoader学习总结

    Java ClassLoader学习总结 Java 类加载机制是 Java 中一个非常重要的机制,它负责加载 Class 文件到 JVM,以供程序使用。ClassLoader 是 Java 中的一个抽象类,它的主要作用是加载 Class 文件到 JVM 中。...

    Java类动态加载(一)——java源文件动态编译为class文件

    这篇博客“Java类动态加载(一)——java源文件动态编译为class文件”可能主要探讨了如何在运行时将Java源代码(.java)编译成对应的字节码文件(.class),并将其加载到Java虚拟机(JVM)中。以下是对这个主题的详细解析...

    java中classLoader的使用

    Java中的类加载器(ClassLoader)是Java虚拟机(JVM)的一个重要组成部分,它负责将类的.class文件从文件系统或者网络中加载到内存中,并转换为对应的Class对象。类加载器的工作流程主要包括加载、验证、准备、解析...

Global site tag (gtag.js) - Google Analytics