[Translation] How Java Class Loaders Work

Source: http://www.cnblogs.com/gaopeng527/p/5246707.html

 

 

The role of the Java class loader is to load classes at runtime. Java class loaders are based on three mechanisms: delegation, visibility, and singularity. The delegation mechanism refers to passing the request to load a class to the parent class loader. If the parent class loader cannot find or load the class, then load it again. The principle of visibility is that the child class loader can see all the classes loaded by the parent class loader, but the parent class loader cannot see the classes loaded by the child class loader. The principle of singularity means that a class is loaded only once, which is ensured by the delegation mechanism to ensure that the child class loader will not load the class loaded by the parent class loader again. A proper understanding of class loaders can help you resolve NoClassDefFoundError and java.lang.ClassNotFoundException as they relate to class loading. Class loaders are also often an important question in more advanced Java interviews. Java class loaders and how they work and how the classpath works are often asked. Questions like "can a class be loaded by two different class loaders" are also frequently asked in Java interview questions. In this tutorial, we will learn what a class loader is, how it works and a few things to know about class loaders.

What is a class loader

A class loader is a class used to load class files. Java source code is compiled into class files by the javac compiler. The JVM then executes the bytecode in the class file to execute the program. Class loaders are responsible for loading class files from the file system, network, or other sources. There are three class loaders used by default: Bootstrap class loader, Extension class loader and System class loader (or called Application class loader). Each class loader has settings for where to load classes from.

  • The Bootstrap class loader is responsible for loading the JDK class files in rt.jar, which is the parent loader of all class loaders. Bootstrap class loader does not have any parent class loader, if you call String.class.getClassLoader(), it will return null, any code based on this will throw NUllPointerException exception. Bootstrap loaders are called initial class loaders.
  • Extension will first delegate the request to load the class to its parent loader, which is Bootstrap. If it is not successfully loaded, it will load the class from the jre/lib/ext directory or the directory defined by the java.ext.dirs system property . The Extension loader is implemented by sun.misc.Launcher$ExtClassLoader.
  • The third default loader is the System class loader (also known as the Application class loader). It is responsible for loading some application-related classes from the classpath environment variable, which is usually defined by the -classpath or -cp command line option, or the classpath attribute of the Manifest in the JAR. The Application class loader is a child loader of the Extension class loader. Implemented by sun.misc.Launcher$AppClassLoader.

Except for the Bootstrap class loader, which is mostly written in C, other class loaders are implemented through java.lang.ClassLoader.

To summarize, here is where the three class loaders load class files:

1) Bootstrap class loader – JRE/lib/rt.jar

2) Extension class loader – the directory pointed to by JRE/lib/ext or java.ext.dirs

3) Application class loader – the CLASSPATH environment variable, defined by the -classpath or -cp option, or the classpath attribute of the Manifest in the JAR.

 

How classloaders work

I've mentioned before that classloaders work based on three mechanisms: delegation, visibility, and singularity. In this section, we look at these rules in detail and use an example to understand how they work. Shown below is how the class loader works using the delegation mechanism.

delegation mechanism

When a class is loaded and initialized, the class is loaded only when it needs to be loaded. Suppose you have a class called Abc.class that your application needs. The first request to load this class is delegated by the Application class loader to its parent class loader, the Extension class loader, and then to the Bootstrap class loader. The Bootstrap class loader will first check if there is this class in rt.jar, because there is no such class, so the request is returned to the Extension class loader, it will check whether there is this class in the jre/lib/ext directory, if This class is found by the Extension class loader, then it will be loaded, and the Application class loader will not load this class; and if the class is not found by the Extension class loader, then the Application class loader will look for it from the classpath . Remember that classpath defines the loading directory of class files, and PATH defines the execution path of executable programs such as javac, java, etc.

 


Visibility Mechanism

According to the visibility mechanism, the child class loader can see the classes loaded by the parent class loader, but not vice versa. So in the following example, when Abc.class has been loaded by the Application class loader, then if you want to use the Extension class loader to load this class, a java.lang.ClassNotFoundException will be thrown.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

package test;

 

    import java.util.logging.Level;

    import java.util.logging.Logger;

 

    /**

     * Java program to demonstrate How ClassLoader works in Java,

     * in particular about visibility principle of ClassLoader.

     *

     * @author Javin Paul

     */

 

    public class ClassLoaderTest {

 

        public static void main(String args[]) {

            try {         

                //printing ClassLoader of this class

                System.out.println("ClassLoaderTest.getClass().getClassLoader() : "

                                     + ClassLoaderTest.class.getClassLoader());

 

                //trying to explicitly load this class again using Extension class loader

                Class.forName("test.ClassLoaderTest", true

                                ,  ClassLoaderTest.class.getClassLoader().getParent());

            } catch (ClassNotFoundException ex) {

                Logger.getLogger(ClassLoaderTest.class.getName()).log(Level.SEVERE, null, ex);

            }

        }

 

    }

 

output:

1

2

3

4

5

6

7

8

9

10

11

12

13

ClassLoaderTest.getClass().getClassLoader() : sun.misc.Launcher$AppClassLoader@601bb1

16/08/2012 2:43:48 AM test.ClassLoaderTest main

SEVERE: null

java.lang.ClassNotFoundException: test.ClassLoaderTest

        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)

        at java.security.AccessController.doPrivileged(Native Method)

        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)

        at sun.misc.Launcher$ExtClassLoader.findClass(Launcher.java:229)

        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)

        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

        at java.lang.Class.forName0(Native Method)

        at java.lang.Class.forName(Class.java:247)

        at test.ClassLoaderTest.main(ClassLoaderTest.java:29)

 

单一性机制

根据这个机制,父加载器加载过的类不能被子加载器加载第二次。虽然重写违反委托和单一性机制的类加载器是可能的,但这样做并不可取。你写自己的类加载器的时候应该严格遵守这三条机制。

如何显式的加载类

Java提供了显式加载类的API:Class.forName(classname)和Class.forName(classname, initialized, classloader)。就像上面的例子中,你可以指定类加载器的名称以及要加载的类的名称。类的加载是通过调用 java.lang.ClassLoader的loadClass()方法,而loadClass()方法则调用了findClass()方法来定位相应 类的字节码。在这个例子中Extension类加载器使用了java.net.URLClassLoader,它从JAR和目录中进行查找类文件,所有 以”/”结尾的查找路径被认为是目录。如果findClass()没有找到那么它会抛出 java.lang.ClassNotFoundException异常,而如果找到的话则会调用defineClass()将字节码转化成类实例,然后 返回。

什么地方使用类加载器

类加载器是个很强大的概念,很多地方被运用。最经典的例子就是AppletClassLoader,它被用来加载Applet使用的类,而 Applets大部分是在网上使用,而非本地的操作系统使用。使用不同的类加载器,你可以从不同的源地址加载同一个类,它们被视为不同的类。J2EE使用 多个类加载器加载不同地方的类,例如WAR文件由Web-app类加载器加载,而EJB-JAR中的类由另外的类加载器加载。有些服务器也支持热部署,这 也由类加载器实现。你也可以使用类加载器来加载数据库或者其他持久层的数据。

以上是关于类加载器的工作原理。我们已经知道了委托、可见性以及单一性原理,这些对于调试类加载器相关问题时至关重要。这些对于Java程序员和架构师来说都是必不可少的知识。

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326647660&siteId=291194637