Java Classloading Mechanism : ClassLoader & ASM & 动态字节码增强

Setting the class path:
[url]http://docs.oracle.com/javase/7/docs/technotes/tools/findingclasses.html[/url][quote]The[b] default class path[/b] is the current directory. Setting the CLASSPATH variable or using the -classpath command-line option overrides that default, so if you want to include the current directory in the search path, you must include "." in the new settings.[/quote]


ClassLoader装载一个类时:
[b][color=red]自底向上检查是否已装载[/color] - 过程中的每层:在本层cache中发现已装载,则返回这个已装载的类实例,调用结束;发现未加载,继续委托上层。
[color=red]若直至最顶层都未发现该类的已装载实例[/color]:
[color=red]自顶向下尝试装载[/color] - 过程中的每层:经搜索本层path后装载类成功,则返回这个装载成功的类实例,调用结束;装载未成功,将ClassNotFoundException抛给下层,委托下层继续尝试装载。
[color=red]若直至最底层都未装载成功[/color]:
则抛给应用一个ClassNotFoundException。[/b]

Java Class Loading:
[url]http://www.techjava.de/topics/2008/01/java-class-loading/[/url][quote]The loading of Java classes is performed by class loaders (CL), they are responsible for loading classes into the JVM. Simple applications can use the Java platform’s built-in class loading facility to load their classes, more complex applications tend to define their own custom class loaders.

[b]The class loaders in Java are organized in a tree. [color=red]By request a class loader determines if the class has already been loaded in the past, looking up in its own cache. If the class is present in the cache the CL returns the class, if not, it delegates the request to the parent. If the parent is not set (is Null) or can not load the class and throws a ClassNotFoundException the classloader tries to load the class itself and searches its own path for the class file. If the class can be loaded it is returned, otherwise a ClassNotFoundException is thrown. The cache lookup goes on recursively from child to parent, until the tree root is reached or a class is found in cache. If the root is reached the class loaders try to load the class and unfold the recursion from parent to child.[/color] Summarizing that we have following order:
[list]
[*]Cache
[*]Parent
[*]Self
[/list]This mechanism ensures that [color=red]classes tending to be loaded by class loaders nearest to the root. Remember, that parent class loader is always has the opportunity to load a class first[/color]. It is important to ensure that core Java classes are loaded by the bootstrap loader, which [color=red]guarantees that the correct versions of classes such as java.lang.Object are loaded[/color]. Furthermore it ensures, that one class loader sees only classes loaded by itself or its parent (or further ancestors) and it cannot see classes loaded by its children or siblings![/b]

The picture illustrates the hierarchy of class loaders. Root loader is bootstrap class loader which has native implementation and cannot be instantiated by Java code.
[img]http://www.techjava.de/wp-content/uploads/JavaClassLoading/clhierarchy.gif[/img]
[/quote]


The Java Tutorials -> Understanding Extension Class Loading:
[url]http://download.oracle.com/javase/tutorial/ext/basics/load.html[/url][quote]When the runtime environment needs to load a new class for an application, it looks for the class in the following locations, in order:
[b]1[/b] Bootstrap classes: the runtime classes in rt.jar, internationalization classes in i18n.jar, and others.
[b]2[/b] Installed extensions: classes in JAR files in the lib/ext directory of the JRE, and in the system-wide, platform-specific extension directory (such as /usr/jdk/packages/lib/ext on the SolarisTM Operating System, but note that use of this directory applies only to JavaTM 6 and later).
[b]3[/b] The class path: classes, including classes in JAR files, on paths specified by the system property java.class.path. If a JAR file on the class path has a manifest with the Class-Path attribute, JAR files specified by the Class-Path attribute will be searched also. By default, the java.class.path property's value is ., the current directory. You can change the value by using the -classpath or -cp command-line options, or setting the CLASSPATH environment variable. The command-line options override the setting of the CLASSPATH environment variable.

The precedence list tells you, for example, that the class path is searched only if a class to be loaded hasn't been found among the classes in rt.jar, i18n.jar or the installed extensions.

Unless your software instantiates its own class loaders for special purposes, you don't really need to know much more than to keep this precedence list in mind. In particular, you should be aware of any class name conflicts that might be present. For example, if you list a class on the class path, you'll get unexpected results if the runtime environment instead loads another class of the same name that it found in an installed extension.


[b][color=red]The Java Class Loading Mechanism:[/color][/b]
The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.

Here are some highlights of the class-loading API:
[list]
[*]Constructors in java.lang.ClassLoader and its subclasses allow you to specify a parent when you instantiate a new class loader. If you don't explicitly specify a parent, the virtual machine's system class loader will be assigned as the default parent.
[*]The loadClass method in ClassLoader performs these tasks, in order, when called to load a class:
[b]1[/b] If a class has already been loaded, it returns it.
[b]2[/b] Otherwise, it delegates the search for the new class to the parent class loader.
[b]3[/b] If the parent class loader does not find the class, loadClass calls the method findClass to find and load the class.
[*]The findClass method of ClassLoader searches for the class in the current class loader if the class wasn't found by the parent class loader. You will probably want to override this method when you instantiate a class loader subclass in your application.
[*]The class java.net.URLClassLoader serves as the basic class loader for extensions and other JAR files, overriding the findClass method of java.lang.ClassLoader to search one or more specified URLs for classes and resources.
[/list]
[/quote]


Java Security Architecture -> 5 Secure Class Loading:
[url]http://download.oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html[/url][quote][color=red]5.1 Class Loader Class Hierarchies[/color]
When loading a class, because [b]there can be multiple instances of class loader objects in one Java Virtual Machine[/b], an important question is how do we determine which class loader to use.

[color=red]5.2 The Primordial Class Loader[/color]
[b]Because each class is loaded by its class loader, and each class loader itself is a class and must be loaded by another class loader, we seem to have the obvious chicken-and-egg problem, i.e., where does the first class loader come from? There is a "primordial'' class loader that bootstraps the class loading process. The primordial class loader is generally written in a native language, such as C, and does not manifest itself within the Java context. The primordial class loader often loads classes from the local file system in a platform-dependent manner.

Some classes, such as those defined in the java.* package, are essential for the correct functioning of the Java Virtual Machine and runtime system. They are often referred to as base classes. Due to historical reasons, all such classes have a class loader that is a null. This null class loader is perhaps the only sign of the existence of a primordial class loader. In fact, it is easier to simply view the null class loader as the primordial class loader.

Given all classes in one Java application environment, we can easily form a class loading tree to reflect the class loading relationship. Each class that is not a class loader is a leaf node. Each class's parent node is its class loader, with the null class loader being the root class. Such a structure is a tree because there cannot be cycles -- a class loader cannot have loaded its own ancestor class loader.[/b]

[color=red]5.3 Class Loader Delegation[/color]
[b]When one class loader is asked to load a class, this class loader either loads the class itself or it can ask another class loader to do so. In other words, the first class loader can delegate to the second class loader. The delegation relationship is virtual in the sense that it has nothing to do with which class loader loads which other class loader. Instead, the delegation relationship is formed when class loader objects are created, and in the form of a parent-child relationship. Nevertheless, the system class loader is the delegation root ancestor of all class loaders. Care must be taken to ensure that the delegation relationship does not contain cycles. Otherwise, the delegation process may enter into an infinite loop.[/b]

[color=red]5.4 Class Resolution Algorithm[/color]
The default implementation of the Java 2 SDK ClassLoader method for loading a class searches for classes in the following order:
[b][list]
[*]Check if the class has already been loaded.
[*]If the current class loader has a specified delegation parent, delegate to the parent to try to load this class. If there is no parent, delegate to the primordial class loader.
[*]Call a customizable method to find the class elsewhere.
[/list][/b]
Here, [b]the first step looks into the class loader's local cache (or its functional equivalent, such as a global cache) to see if a loaded class matches the target class. The last step provides a way to customize the mechanism for looking for classes[/b]; thus a custom class loader can override this method to specify how a class should be looked up. For example, an applet class loader can override this method to go back to the applet host and try to locate the class file and load it over the network.

[b]If at any step a class is located, it is returned. If the class is not found using the above steps, a ClassNotFound exception is thrown.[/b]

[b]Observe that it is critical for type safety that the same class not be loaded more than once by the same class loader. If the class is not among those already loaded, the current class loader attempts to delegate the task to the parent class loader. This can occur recursively. This ensures that the appropriate class loader is used. For example, when locating a system class, the delegation process continues until the system class loader is reached.[/b]

We have seen the delegation algorithm earlier. But, given the name of any class, which class loader do we start with in trying to load the class? The rules for determining the class loader are the following:
[color=red][b][list]
[*]When loading the first class of an application, a new instance of the URLClassLoader is used.
[*]When loading the first class of an applet, a new instance of the AppletClassLoader is used.
[*]When java.lang.Class.ForName is directly called, the primordial class loader is used.
[*]If the request to load a class is triggered by a reference to it from an existing class, the class loader for the existing class is asked to load the class.
[/list][/b][/color][/quote]


Understanding the Java ClassLoader([b]见PDF附件,务须精读![/b]):
[url]http://www.ibm.com/developerworks/java/tutorials/j-classloader/[/url]


Java programming dynamics, Part 1: Java classes and class loading:
[url]http://www.ibm.com/developerworks/java/library/j-dyn0429/[/url]
[b][size=medium]Java programming dynamics系列总共 8 parts,都不错!作者是牛人。读之![/size][/b]


Understanding the Java Classloading Mechanism:
[url]http://www2.sys-con.com/itsg/virtualcd/java/archives/0808/chaudhri/index.html[/url][quote][b]The smallest unit of execution that gets loaded by a ClassLoader is the Java class file[/b]. A class file contains the binary representation of a Java class, which has the executable bytecodes and references to other classes used by that class, including references to classes in the Java API. Stated simply, a ClassLoader locates the bytecodes for a Java class that needs to be loaded, reads the bytecodes, and creates an instance of the java.lang.Class class. This makes the class available to the JVM for execution. [b]Initially when a JVM starts up, nothing is loaded into it. The class file of the program being executed is loaded first and then other classes and interfaces are loaded as they get referenced in the bytecode being executed. The JVM thus exhibits lazy loading[/b], i.e., loading classes only when required, so at start-up the JVM doesn't need to know the classes that would get loaded during runtime. Lazy loading plays a key role in providing dynamic extensibility to the Java platform.

The following is a high-level class-loading algorithm executed by a ClassLoader when a client requests it to load a class:
1. A check is performed to see if the requested class has already been loaded by the current ClassLoader. If so, the loaded class is returned and the request is completed. The JVM caches all the classes that are loaded by a ClassLoader. A class that has previously been loaded by a ClassLoader is not loaded again.
2. If the class is not already loaded, the request is delegated to the parent ClassLoader, before the current ClassLoader tries to load it. This delegation can go all the way up to the bootstrap ClassLoader, after which no further delegation is possible.
3. If a parent fails to return a class because it was unable to load it, the current ClassLoader will then try to search for the requested class. Each ClassLoader has defined locations where it searches for classes to load. For instance, the bootstrap ClassLoader searches in the locations (directories and zip/jar files) specified in the sun.boot.class.path system property. The system ClassLoader searches for classes in the locations specified by the classpath (set as the java.class.path system property) command-line variable passed in when a JVM starts executing. If the class is found, it's loaded into the system and returned, completing the request.
4. If the class is not found, a java.lang.ClassNotFoundException is thrown.[/quote]


The basics of Java class loaders:
[url]http://www.javaworld.com/javaworld/jw-10-1996/jw-10-indepth.html[/url]


ClassLoader : Java Glossary:
[url]http://mindprod.com/jgloss/classloader.html[/url]


[url]http://www.iteye.com/topic/136427[/url][img]http://photo2.bababian.com/usr832855/upload1/20090604/sCb1i6ey4kVKcO1KlZX43TkpALe5IrGD_2HHLAS3wJB4q4SdDpZpPIw==.jpg[/img]


深入探讨 Java 类加载器:
[url]http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html[/url][quote]顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:[b]Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。[/b]实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

基本上所有的类加载器都是 java.lang.ClassLoader 类的一个实例。[b]java.lang.ClassLoader 类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,[color=red]即 java.lang.Class 类的一个实例[/color][/b]。

除了引导类加载器之外,所有的类加载器都有一个父类加载器。
[img]http://www.ibm.com/developerworks/cn/java/j-lo-classloader/image001.jpg[/img]

每个 Java 类(补充:即每个Class实例对象)都维护着一个指向定义它的类加载器的引用,通过 getClassLoader() 方法就可以获取到此引用。

[b]类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理([color=red]注:这里的代理指的是delegate,叫委托更好点[/color])给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。[/b]在介绍代理模式背后的动机之前,首先需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。[b]Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。[/b]比如一个 Java 类 com.example.Sample,编译之后生成了字节代码文件 Sample.class。两个不同的类加载器 ClassLoaderA 和 ClassLoaderB 分别读取了这个 Sample.class 文件,并定义出两个 java.lang.Class 类的实例来表示这个类。这两个实例是不相同的。对于 Java 虚拟机来说,它们是不同的类。试图对这两个类的对象进行相互赋值,会抛出运行时异常 ClassCastException。

代理模式是为了保证 Java 核心库的类型安全。所有 Java 应用都至少需要引用 java.lang.Object 类,也就是说在运行的时候,java.lang.Object 这个类需要被加载到 Java 虚拟机中。如果这个加载过程由 Java 应用自己的类加载器来完成的话,很可能就存在多个版本的 java.lang.Object 类,而且这些类之间是不兼容的。[b]通过代理模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。[/b]
不同的类加载器为相同名称的类创建了额外的名称空间。相同名称的类可以并存在 Java 虚拟机中,只需要用不同的类加载器来加载它们即可。不同类加载器加载的类之间是不兼容的,这就相当于在 Java 虚拟机内部创建了一个个相互隔离的 Java 类空间。

在前面介绍类加载器的代理模式的时候,提到过类加载器会首先代理给其它类加载器来尝试加载某个类。[b]这就意味着真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。真正完成类的加载工作是通过调用 defineClass 来实现的;而启动类的加载过程是通过调用 loadClass 来实现的。前者称为一个类的定义加载器(defining loader),后者称为初始加载器(initiating loader)。[color=red]在 Java 虚拟机判断两个类是否相同的时候,使用的是类的定义加载器。也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。[/color][/b]两种类加载器的关联之处在于:一个类的定义加载器是它引用的其它类的初始加载器。如类 com.example.Outer 引用了类 com.example.Inner,则由类 com.example.Outer 的定义加载器负责启动类 com.example.Inner 的加载过程。
方法 loadClass() 抛出的是 java.lang.ClassNotFoundException 异常;方法 defineClass() 抛出的是 java.lang.NoClassDefFoundError 异常。
类加载器在成功加载某个类之后,会把得到的 java.lang.Class 类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。也就是说,[b]对于一个类加载器实例来说,相同全名的类只加载一次,即 loadClass 方法不会被重复调用。[/b]
[/quote]


ClassLoader的加载过程及分析一:
[url]http://www.iteye.com/topic/703842[/url][quote]虚拟机一启动,会先做一些初始化的动作。一旦初始化动作完成之后,就会产生第一个类别加载器,即所谓的Bootstrap Loader,Bootstrap Loader 是由C++ 所撰写而成,这个Bootstrap Loader所做的初始工作中,除了也做一些基本的初始化动作之外,最重要的就是加载定义在sun.misc 命名空间底下的Launcher.java 之中的ExtClassLoader( 因为是inner class ,所以编译之后会变成Launcher$ExtClassLoader.class) ,并设定其Parent 为null,代表其父加载器为Bootstrap Loader 。然后Bootstrap Loader ,再要求加载定义于sun.misc 命名空间底下的Launcher.java 之中的AppClassLoader( 因为是inner class,所以编译之后会变成Launcher$AppClassLoader.class) ,并设定其Parent 为之前产生的ExtClassLoader 实例。

AppClassLoader 和ExtClassLoader 都是URLClassLoader 的子类别。由于它们都是URLClassLoader 的子类别,所以它们也应该有URL 作为搜寻类别档的参考,由原始码中我们可以得知,AppClassLoader 所参考的URL 是从系统参java.class.path 取出的字符串所决定,而java.class.path 则是由我们在执行java.exe 时,利用 –cp 或-classpath 或CLASSPATH 环境变量所决定。
[/quote]
[b][size=medium]提醒我:关于JVM启动过程记得把附件中的 Using the BootClasspath.pdf 好好看看![/size]
[/b]

classloader相关基础知识:
[url]http://www.iteye.com/topic/25053[/url][quote]java动态载入class的两种方式:
1)implicit隐式,即利用实例化才载入的特性来动态载入class
2)explicit显式方式,又分两种方式:
1)java.lang.Class的forName()方法
2)java.lang.ClassLoader的loadClass()方法[/quote]


深入了解Java ClassLoader、Bytecode 、ASM、cglib:
[url]http://www.iteye.com/topic/98178[/url]


Java类加载原理解析第一篇(上):
[url]http://weiwu83.iteye.com/blog/141207[/url]
Java类加载原理解析第一篇(下):
[url]http://weiwu83.iteye.com/blog/141208[/url]


JDK引述:[quote]
Every Class object(每个Class类的实例对象) contains a reference to the ClassLoader that defined it.


protected Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException

Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
[b]
1.[color=red]Invoke findLoadedClass(String) to check if the class has already been loaded.[/color]
2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
3.Invoke the findClass(String) method to find the class.
[/b]
If the class was found using the above steps, and the resolve flag is true, this method will then invoke the resolveClass(Class) method on the resulting Class object.

Subclasses of ClassLoader are encouraged to override findClass(String), rather than this method. [/quote]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值