`
Technoboy
  • 浏览: 154026 次
  • 性别: 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类加载器)

    自己收集的java class loader相关的一些网络资源文档, 希望对大家有所帮助

    Java Class Loader总结.doc

    Java Class Loader总结

    java 类加载器 class loader

    java 类加载器 class loaderjava 类加载器 class loaderjava 类加载器 class loaderjava 类加载器 class loaderjava 类加载器 class loaderjava 类加载器 class loaderjava 类加载器 class loader

    深入Class Loader

    深入 Java 的Class Loader(类加载器)

    class loader

    Dynamic class loading in the Java Virtual Machine

    深入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经典入门教程pdf完整版

    loader Byte code Verifier Javac Hello.java Netwo Hello class Interpreter code Runtime generator/ Hardware 1:编写代码 首先把我们想要计算机做的事情,通过Java表达出来,写成Java文件,这个过程就是 编写代码的...

    Class Loader:在没有命令提示符的情况下执行Java .class文件-开源

    Class Loader 是一个可视化的基本 .net 2.0 软件。 使用类加载器,您可以在没有命令提示符的情况下执行 .class 文件。 只需打开类文件!

    js-class-loader:(Java) 快速 Javascript 聚合器捆绑器,具有依赖项检测功能

    js 类加载器(Java) 一种免费软件工具,用于捆绑和提供具有内置依赖项检测功能的大型 Javascript 代码库。 请参阅网站 和 github 仓库: : 了解更多信息。

    JAVA白皮书(英文版)

    6.2Security Checks in the Class Loader 6.3The Byte Code Verification Process 6.3.1The Byte Code Verifier 6.4Security in the Java Networking Package 6.5Summary 7. Multithreading 7.1...

    深入解析Java中的Class Loader类加载器

    主要介绍了Java中的类加载器,是Java入门学习中的基础知识,需要的朋友可以参考下

    hive-jdbc-1.1.0-cdh5.4.5-standalone.jar

    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:421) at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:412) at org.eclipse.osgi.internal....

    Java常用基础知识-kaic.docx

    你可以创建个新的class loader,然后用loadClass加载,再newInstance;原来加载的classloader是不能重新加载的;这算是一个典型的容器思路。 《深入理解java虚拟机》 2、对java“书写一次,到处运行”(Write once, ...

    hive-jdbc-2.1.0-standalone.jar

    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:421) at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:412) at org.eclipse.osgi.internal....

    Java虚拟机 JVM 内存结构介绍

    描述Java虚拟机规范中关于内存管理的部分 主要介绍Runtime Data Area,包括Java Stack,Native Method Stack, ...还简要介绍了Runtime Data Area周边的模块,包括Class Loader,Execution Engine,Native Interface

    深入Java虚拟机读书笔记1

    Java虚拟机的基本结构图:Java虚拟机包含一个类装载器(class loader),可以从程序和API中装载class文件,其中API只有程序执行时需要的那

    jboss 5 原理 2 classloader

    With OSGi-style classloading getting more and more traction, and a number of new Java modules/classloading specifications on the horizon, it was high time we revamped our classloading layer in order ...

    javacv-platform-1.3.3-src

    The class definitions are basically ports to Java of the original header files in C/C++, and I deliberately decided to keep as much of the original syntax as possible. For example, here is a method ...

    commons-beanutils-1.7.0

    at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:872) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1325) at org.apache.catalina...

    深入探讨 Java 类加载器

    类加载器(class loader)是 Java™ 中的一个很重要的概念。类加载器负责加载 Java 类的字节代码到 Java 虚拟机中。本文首先详细介绍了 Java 类加载器的基本概念,包括代理模式、加载类的具体过程和线程上下文类加载...

Global site tag (gtag.js) - Google Analytics