`
Technoboy
  • 浏览: 157693 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Java Class Loader

    博客分类:
  • J2SE
阅读更多
1. ClassLoader
  类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。

2. ClassLoader Hierarchy
  JVM在加载类时,使用的是双亲委托模式(delegation model),也就是说除了Bootstrap ClassLoader之外,每个ClassLoader都有一个Parent ClassLoader。ClassLoader是按需进行加载class文件。当ClassLoader试图加载一个类时,首先检查本地缓冲,查看类是否已被加载,如果类没有被加载,尝试委托给父ClassLoader进行加载,如果父ClassLoader加载失败,才会由该ClassLoader进行加载,从而避免了重复加载的问题。一下为类装载器层次图:



  Bootstrap ClassLoader:负责加载java_home/lib目录下的核心类或- Xbootclasspath指定目录下的类。
  Extension ClassLoader:负责加载java_home/lib/ext目录下的扩展类或 -Djava.ext.dirs 指定目录下的类。
  System ClassLoader:负责加载-classpath/-Djava.class.path所指的目录下的类。
  如果类App1在本地缓冲中没有class文件(没有被加载),那么它会自底向上依次查找是否已经加载了类,如果已经加载,则直接返回该类实例的引用。如果BootstrapClassLoader也未成功加载该类,那么会抛出异常,然后自顶向下依次尝试加载,如果到App1 ClassLoader还没有加载成功,那么会抛出ClassNotFoundException异常给调用者。
public static void main(String[] args) {
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		while(cl != null){
			System.out.println(cl);
			System.out.println("parent class loader: " + cl.getParent());
			cl = cl.getParent();
		}
	}

sun.misc.Launcher$AppClassLoader@19821f
parent class loader: sun.misc.Launcher$ExtClassLoader@addbf1
sun.misc.Launcher$ExtClassLoader@addbf1
parent class loader: null

  我们看到,当前系统类装载器为AppClassLoader,AppClassLoader的父类装载器是ExtClassLoader,ExtClassLoader的父装载器为null,表示为BootstrapClassLoader。BootstrapClassLoader由JVM采用本地代码实现,因此没有对应的Java类,所以ExtClassLoader的getParent()返回null。
  ClassLoader的职责之一是保护系统名字空间。以下为ClassLoader类部分代码:
private ProtectionDomain preDefineClass(String name,
					    ProtectionDomain protectionDomain)
    {
	if (!checkName(name))
	    throw new NoClassDefFoundError("IllegalName: " + name);

	if ((name != null) && name.startsWith("java.")) {
	    throw new SecurityException("Prohibited package name: " +
					name.substring(0, name.lastIndexOf('.')));
	}
	if (protectionDomain == null) {
	    protectionDomain = getDefaultDomain();
	}

	if (name != null)
	    checkCerts(name, protectionDomain.getCodeSource());

	return protectionDomain;
    }

  那么,当我们定义如下类Foo,虽然能够通过编译,但是会报java.lang.SecurityException: Prohibited package name: java.lang异常,因为我们试图将Foo类写入到java.lang包下。
package java.lang;

public class Foo {
    
    public static void main(String args[]) throws Exception {
        Foo f = new Foo();
        System.out.println(f.toString());
    }
}


3. 定制ClassLoader
  Java自带的ClassLoader类的定义为:
public abstract class ClassLoader{ 
}

启动类加载器是JVM通过调用ClassLoader.loadClass()方法。
public Class<?> loadClass(String name) throws ClassNotFoundException {
	return loadClass(name, false);
    }

protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    c = parent.loadClass(name, false);
		} else {
		    c = findBootstrapClass0(name);
		}
	    } catch (ClassNotFoundException e) {
	        // If still not found, then invoke findClass in order
	        // to find the class.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
    }

protected Class<?> findClass(String name) throws ClassNotFoundException {
	throw new ClassNotFoundException(name);
    }

loadClass(String name, boolean resolve)方法中的resolve如果为true,表示分析这个Class对象,包括检查Class Loader是否已经初始化等。loadClass(String name) 在加载类之后不会对该类进行初始化,直到第一次使用该类时,才会对该类进行初始化。
那么,我们在定制ClassLoader的时候,通常只需要覆写findClass(String name)方法。在findClass(String name)方法内,我们可以通过文件、网络(URL)等形式获取字节码。以下为获取字节码的方法:
public InputStream getResourceAsStream(String name);
public URL getResource(String name);
public InputStream getResourceAsStream(String name);
public Enumeration<URL> getResources(String name) throws IOException;

在取得字节码后,需要调用defineClass()方法将字节数组转换成Class对象,该方法签名如下:
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
					 ProtectionDomain protectionDomain)
	throws ClassFormatError

对于相同的类,JVM最多会载入一次。如果同一个class文件被不同的ClassLoader载入(定义),那么载入后的两个类是完全不同的。
public class Foo{
    //
    private static final AtomicInteger COUNTER = new AtomicInteger(0);

    public Foo() {
        System.out.println("counter: " + COUNTER.incrementAndGet());
    }
    
    public static void main(String args[]) throws Exception {
        URL urls[] = new URL[]{new URL("file:/c:/")};
        URLClassLoader ucl1 = new URLClassLoader(urls);
        URLClassLoader ucl2 = new URLClassLoader(urls);
        Class<?> c1 = ucl1.loadClass("Foo");
        Class<?> c2 = ucl2.loadClass("Foo");
        System.out.println(c1 == c2);
        c1.newInstance();
        c2.newInstance();
    }
}

以上程序需要保证Foo.class文件不在classpath路径下。从而使AppClassLoader无法加载Foo.class。
输出结果:
false
counter: 1
counter: 1


4. Web应用的ClassLoader
  绝大多数的EJB容器,Servlet容器等都会提供定制的ClassLoader,来实现特定的功能。但是通常情况下,所有的servlet和filter使用一个ClassLoader。每个jsp都使用一个独立的ClassLoader。

5. 隐式(implicit)和显示(explicit)的加载
  隐式加载:我们使用new关键字实例化一个类,就是隐身的加载了类。
  显示加载分为两种:
     java.lang.Class的forName()方法;
     java.lang.ClassLoader的loadClass()方法。
  Class.forName()方法有两个重载的版本:
 public static Class<?> forName(String className) 
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }

public static Class<?> forName(String name, boolean initialize,
				   ClassLoader loader)
        throws ClassNotFoundException

可以看出,forName(String className)默认以true和ClassLoader.getCallerClassLoader()调用了三参数的重载方法。ClassLoader.getCallerClassLoader()表示以caller class loader加载类,并会初始化类(即静态变量会被初始化,静态初始化块中的代码也会被执行)。如果以false和ClassLoader.getCallerClassLoader()调用三参数的重载方法,表示加载后的类不会被初始化。
ClassLoader.loadClass()方法在类加载后,也同样不会初始化类。

6. 两个异常(exception)
  NoClassDefFoundError: 当java源文件已编译成.class文件,但是ClassLoader在运行期间搜寻路径load某个类时,没有找到.class文件则抛出这个异常。
  ClassNotFoundException: 试图通过一个String变量来创建一个Class类时不成功则抛出这个异常
34
6
分享到:
评论
7 楼 Technoboy 2011-04-29  
xijunhu 写道
energykey 写道
java.lang.ClassLoader源代码第2046行有惊喜!(not a joke)

是这个 ,好多行都有,放到文本文档中显示的是一大家都认识的符号。

这是什么情况?
6 楼 biucb 2011-04-26  
有点深入java虚拟机的感觉
5 楼 Summer花的姿态 2011-04-24  
  
4 楼 xijunhu 2011-04-19  
energykey 写道
java.lang.ClassLoader源代码第2046行有惊喜!(not a joke)

是这个 ,好多行都有,放到文本文档中显示的是一大家都认识的符号。
3 楼 energykey 2011-04-19  
java.lang.ClassLoader源代码第2046行有惊喜!(not a joke)
2 楼 Technoboy 2011-04-18  
randi0624 写道
学习学习。。等我们这些小菜 慢慢通透一切原理,那时表示一切都是浮云。。还渴望大师些多多来点精贴。

1 楼 randi0624 2011-04-18  
学习学习。。等我们这些小菜 慢慢通透一切原理,那时表示一切都是浮云。。还渴望大师些多多来点精贴。

相关推荐

    java class loader(JAVA类加载器)

    遇到类冲突、类找不到等问题时,可通过设置JVM参数`-verbose:class`来查看类加载的详细信息,或者使用JDK的`jmap -histo`命令分析内存中的类加载情况。 8. **线程安全** 类加载过程中的某些步骤,如加载和初始化...

    Java Class Loader总结.doc

    System.out.println("parent class loader: " + cl.getParent()); cl = cl.getParent(); } ``` 这段代码会打印出当前的类加载器以及它们的父加载器。通常,你会看到AppClassLoader(系统类加载器)、...

    java class加密保护工具

    本工具是对java class文件进行加密保护的工具!本工具全面支持linux/unix/windows操作系统。 众所周知,java编译后的class文件是一种中间字节字文件, 很容易被反编译工具反编译,而传统的java源代码保护方法基本都是...

    java 类加载器 class loader

    创建自定义类加载器通常需要继承`java.lang.ClassLoader`,重写`findClass()`或`loadClass()`方法,从而控制类的查找和加载过程。这使得开发者能够在运行时根据需要加载特定的类,比如从网络、数据库或其他非传统...

    java class加密保护(完全免费) v2.1

    本工具是对java class文件进行加密保护防止反编译的工具!本工具全面支持linux/unix/windows操作系统。 继推出v1.0版本后,获得了用户大量的支持与的反馈,我们再次推出本v2.0版,对加密算法进行了更大的改进,安全...

    JDK17-security-developer-guide.pdf

    JVM 负责执行 Java 字节码,Java Class Loader 负责加载类文件,而 Java Security Manager 则负责实施安全策略。 Java 安全协议 Java 安全协议是指 Java 平台使用的安全协议,包括 SSL/TLS、HTTPS 等。这些协议...

    JDK19-jdk-migration-guide.pdf

    * Java Class Loader:Java Class Loader 负责加载和管理 Java 类文件。 * Java Native Interface(JNI):JNI 是 Java 平台标准版提供的一种机制,用于将 Java 代码与 native 代码集成。 4.Java 平台标准版的新...

    javagui开发俄罗斯方块游戏.doc

    2. Java Class Loader: Class Loader 负责加载和链接 Java 字节码,提供了类加载和解析的功能。 3. Java Native Interface(JNI): JNI 是 Java 平台和 native 代码之间的接口,提供了 Java 和 native 代码之间的...

    JDK9-JSE-Tools Reference-319.pdf

    本手册还涵盖了 Java SE 9 中的其他工具和命令,例如 Java 任务计划器(java)、Java Class Loader(java.lang.ClassLoader)等。 在本手册中,我们将详细介绍每个工具和命令的使用方法、参数设置和示例代码,以...

    loader in java houtian

    Java加载器(Loader)是Java虚拟机(JVM)的核心组成部分,主要负责将类的字节码文件加载到JVM中并转换为运行时的数据结构。在深入理解这个概念之前,我们首先要明白Java的类加载机制。Java的类加载过程包括加载、...

    深入Class Loader

    ### 深入理解Java的Class Loader:动态性与灵活性的核心 #### 一、Class Loader在Java中的核心地位 在Java编程的世界里,类加载器(Class Loader)扮演着极其关键的角色,它不仅支撑起了Java的动态性,还极大地...

    Java虚拟机class文件原理

    Java虚拟机(JVM)的Class文件原理是Java程序运行的基础。Java中的所有类都必须先被装载到JVM中才能被执行,这个过程由JVM内的类装载器(ClassLoader)来完成。类装载器的工作是将类文件从硬盘读取到内存中,使得JVM...

    认识Java的Class类.doc

    Java的Class类是Java反射机制的核心,它代表了Java中的每一个类和接口。Class类的主要功能是提供关于类的信息,包括类的结构、属性、方法等。以下是对Java Class类的详细说明: 1. **Class类对象的创建**:在Java中...

    loaderrunner测试脚本

    - `public class Actions { ... }` 主类定义,包含了所有的成员变量和方法。 #### 四、核心方法解析 1. **`init()`**:初始化方法负责加载配置文件、登录系统、初始化参数等基础工作。 - **配置加载**:`load_...

    class-loader测试工程

    在Java编程语言中,类加载器(Class-Loader)是一个至关重要的组件,它负责加载类到JVM(Java虚拟机)中。这个“class-loader测试工程”可能是一个专门设计用于研究和理解Java类加载机制的项目。在Java中,类加载...

    java虚拟机原理java虚拟机原理.docx

    类加载器(Class Loader)是JVM中的一个重要组件,负责将Java字节码文件加载到JVM内存中。类加载器可以分为四种:Bootstrap Class Loader、Extension Class Loader、System Class Loader和User-Defined Class Loader...

    class loader

    ### 动态类加载在Java虚拟机中的应用 #### 概述 动态类加载是Java虚拟机(JVM)的一项核心特性,它为Java平台带来了强大的功能:即能够在运行时安装软件组件。这一机制不仅提高了系统的灵活性,还优化了资源管理。...

    java基础测试.doc

    装载过程是由类加载器(Class Loader)完成的,类加载器分为应用程序类加载器(Application Class Loader)、扩展类加载器(Extension Class Loader)和引导类加载器(Bootstrap Class Loader)。每个类加载器都有特定的任务...

    深入java虚拟机(inside the java virtual machine)

    The Class Loader Architecture The Java Class File The Java API The Java Programming Language Architectural Tradeoffs Future Trends On the CD-ROM The Resources Page 2 Platform independence Why ...

    在Java的反射中,Class.forName和Class

    `Class.forName`实际上依赖于当前线程的上下文类加载器(Context Class Loader)。如果类已经加载,`forName`会直接返回该类的`Class`对象;否则,它会使用当前线程的上下文类加载器来加载类。而`ClassLoader`通常...

Global site tag (gtag.js) - Google Analytics