Detailed explanation and use of Classloader

Very well written, reproduced for your reference

Address: https://www.cnblogs.com/kabi/p/6124761.html

ClassLoader mainly provides services for class requests. When JVM needs a certain class, it asks ClassLoader for this class according to its name, and then ClassLoader returns the class object of this class. 1.1 Several related concepts ClassLoader is responsible for loading all resources of the system (Class, file, byte stream from the network, etc.), and loads resources into JVM through ClassLoader 
. Each class has a reference that points to its own ClassLoader. Class.getClassLoader() 
The ClassLoader of an array is the ClassLoader of its elements. If it is a basic data type, this array does not have a ClassLoader 
1.2 Main Methods and Working Process In Java1.1 and previous versions, the main methods of ClassLoader: 
Class loadClass( String name, boolean resolve ); ClassLoader.loadClass() is the entry point  of the ClassLoader The
defineClass method is the main trick of the ClassLoader. This method takes an array of raw bytes and converts it into a Class object. Primitive arrays contain data as loaded from the file system or network. 
The findSystemClass method loads files from the local file system. It looks for a class file in the local filesystem, and if it exists, converts the file to a class using defineClass to convert the raw bytes into a Class object. This is the default mechanism by which the JVM normally loads classes when running a Java application. 
resolveClass can load a class partially (without resolution) or fully (with resolution). When writing our own loadClass, resolveClass can be called, depending on the value of loadClass's resolve parameter 
findLoadedClass acts as a cache: when loadClass is requested to load a class, it calls this method to see if the ClassLoader has already loaded the class, which allows Avoid the hassle of reloading existing classes. This method should be called first. The 
general load method process is as follows: 

call findLoadedClass to see if there is a loaded class. 
If not, then use some special magic way to get the raw bytes. (via IO from the filesystem, a stream of bytes from the network, etc.) 
If there are already raw bytes, call defineClass to convert them into Class objects. 
If there are no raw bytes, then call findSystemClass to see if the class is fetched from the local filesystem. 
If the resolve parameter is true, call resolveClass to resolve the Class object. 
Returns ClassNotFoundException if there is no class yet. 
Otherwise, return the class to the calling program. 
1.3 Delegate Model Since JDK1.2, ClassLoader has been improved and used the delegation model. All ClassLoaders in the system form a tree. When ClassLoader loads the class library, it asks the Parent to find it first, and the Parent finds it when it cannot find it. 
JVM will generate three ClassLoader at runtime, Bootstrap ClassLoader, Extension ClassLoader and App ClassLoader. Among them, Bootstrap ClassLoader is written in C++, it is not seen in Java, it is null. It is used to load the core class library, which is the class library under lib, the Extension ClassLoader loads the class library under lib/ext, and the App ClassLoader loads the class library in the Classpath. The relationship between the three is: the Parent of the App ClassLoader is the Extension ClassLoader, The Parent of Extension ClassLoader is Bootstrap ClassLoader. When loading a class, BootStrap first searches it, if it cannot be found, it is searched by Extension ClassLoader, and finally App ClassLoader. 

An important reason to design the ClassLoader as a delegate model is for security reasons, such as in an Applet, if a java.lang.String class is written and is destructive. If this delegation mechanism is not adopted, this destructive String will be loaded on the user's machine, resulting in the destruction of user security. But this is not the case with this delegation mechanism. Because the system will eventually be loaded by Bootstrap when the java.lang.String class is to be loaded, this destructive String never gets a chance to load. 

The delegation model also brings some problems, which can cause confusion in some cases. The following is the structure diagram of Tomcat's ClassLoader: 

                Bootstrap
                  |
                System
                  |
                Common
                /    
            Catalina Shared
                      /    
                   Webapp1 Webapp2 ...

Classes loaded by the Common class loader must never (by name) directly access classes loaded by the web application. The only way to tie these classes together is through the use of interfaces that are visible to both sets of classes. In this case, it contains javax.servlet.Servlet implemented by a Java servlet. 
If a class library such as lib or lib/ext has the same class as in the application, the class in the application will not be loaded. Usually there will be problems when the class library is moved in the new jdk version. For example, initially we used our own xml parser, but in jdk1.4, the xml parser becomes the standard class library, and the priority of load is also higher than our own. xml parser, our own xml parser can never be found, which may cause our application to fail to run. 

The same class, different ClassLoader, will cause ClassCastException 

1.4 ClassLoader in thread Each running thread has a member contextClassLoader, which is used to dynamically load other classes at runtime, you can use the method Thread.currentThread(). setContextClassLoader(...); Change the contextClassLoader of the current thread to change its behavior of loading classes; you can also get the ClassLoader of the current thread through the method Thread.currentThread().getContextClassLoader(). 
In fact, all programs in Java applications run in threads. If the ClassLoader is not manually set in the program, the ClassLoader obtained by the following two methods for general java classes is usually the same 

this.getClass.getClassLoader(); 
Thread.currentThread().getContextClassLoader(); 
The Classloader obtained by method 1 is static, indicating who the class loader is; the Classloader obtained by method 2 is dynamic, and whoever executes (a thread) is the executor's Classloader. For classes in singleton mode, static classes, etc., after loading once, this instance will be called by many programs (threads). For these classes, the loaded Classloader and the Classloader of the execution thread are usually different. 

1.5 ClassLoader in Web Application Back to the above example, in Tomcat, the working principle of WebApp's ClassLoader is a bit different, it first tries to load the class by itself (load the class in ContextPath/WEB-INF/...), if Unable to load, and then request the parent ClassLoader to complete. 
It can be obtained from this: 

For WEB APP threads, its contextClassLoader is WebAppClassLoader. 
For Tomcat Server threads, its contextClassLoader is CatalinaClassLoader 
1.6 There are several ways to obtain ClassLoader, which can be obtained by the following three methods. ClassLoader 
this.getClass.getClassLoader(); // Use the ClassLoader of the current class 
Thread.currentThread().getContextClassLoader(); // Use the ClassLoader of the current thread 
ClassLoader.getSystemClassLoader(); // Use the system ClassLoader, which is the ClassLoader used by the entry point of the system. (Note that the system ClassLoader is not the same as the root ClassLoader. The system ClassLoader under the JVM is usually the App ClassLoader.) 
1.7 Several Extended Applications Users can customize their own ClassLoader to achieve the following application 
security. The class passes through the ClassLoader before entering the JVM, so you can check whether there is a correct digital signature and other 
encryption here. The java bytecode is easy to be decompiled. By customizing the ClassLoader, the bytecode is encrypted first to prevent others from downloading and then decompiling. The ClassLoader here is equivalent to a dynamic decoder 
archive. Maybe in order to save network resources, do some special archiving of your own code, and then use a custom ClassLoader to unarchive the 
self-expanding program. Compile a java application into a single executable class file, which contains compressed and encrypted class file data, and has a fixed ClassLoader, which is completely unpacked in memory when the program runs, without the need to install 
dynamic generation first. Can generate application classes that have not yet been generated, create entire classes in real-time and introduce JVM 
2.0 resource loading at any time
All resources are loaded into the JVM through ClassLoader, so of course ClassLoader can be used when loading resources, but for different resources, some other methods can be used to load, for example, classes can be directly new, and files can be directly IO Wait. 2.1 Several methods of loading classes Suppose there are class A and class B. A needs to instantiate B in the method amethod. There are three possible methods. For the case of loading classes, the user needs to know the full name of class B (including the package name, such as "com.rain.B") 
1. Use the Class static method Class.forName 

    Class cls = Class.forName("com.rain. B");
    B b = (B)cls.newInstance();

2. Use ClassLoader 
    /* Step 1. Get ClassLoader */
    ClassLoader cl; // How to get ClassLoader refer to 1.6

    /* Step 2. Load the class */
    Class cls = cl.loadClass("com.rain.B"); // Use the ClassLoader obtained in the first step to load B
    
    /* Step 3. new instance */
    B b = (B)cls.newInstance(); / / A class with B gets an instance of B

3. Direct new 
    B b = new B();

2.2 File loading (such as configuration files, etc.) Suppose you want to read the file sys.properties in the folder /com/rain/config in the com.rain.A class. The file can be read through an absolute path or a relative path, an absolute path It is very simple. It starts with the disk number under Windows and starts with "/" under Unix. 
For the relative path, its relative value is relative to the ClassLoader, because the ClassLoader is a tree, so this relative path and any one on the ClassLoader tree ClassLoader can find the file after the relative comparison, then the file can be found. Of course, the delegation model is also used to read the file 

. 1. Direct IO 

/**
 * Assuming the current location is "C:/test", run the following command to run A " java com.rain.A"
 * 1. An absolute path can be used in the program, the absolute path under Windows starts with the disk number, and under Unix it starts with "/"
 * 2. You can also use a relative path, there is no "/ before the relative path. "
 * Because we are executing the program in the "C:/test" directory, the program entry point is "C:/test", and the relative path is
 * "com/rain/config/sys.properties"
 * (In the example, the current program The ClassLoader is the App ClassLoader, the system ClassLoader = the ClassLoader of the current
 * program, and the entry point is "C:/test")
 * For the ClassLoader tree, if the file is under jdk lib, if the file is under jdk lib/ext, if the file is in the environment variable,
 * can be found through the relative path "sys.properties", the files under lib are found first
 */
File f = new File("C:/test/com/rain/config/sys.properties"); // use Absolute path
//File f = new File("com/rain/config/sys.properties"); // Use relative path
InputStream is = new FileInputStream(f);

If it is a configuration file, you can pass java.util.Properties. load(is) reads the content into Properties. Properties default that the encoding of is is ISO-8859-1. If the configuration file is not in English, there may be garbled characters. 
2. Use ClassLoader 

/**
 * Because there are 3 ways to get ClassLoader, there are 3 ways to read files as follows
 * The path used is a relative path relative to the point of this ClassLoader, only relative paths can be used here
 */
InputStream is = null;
is = this.getClass().getClassLoader().getResourceAsStream(
       "com/rain/config/sys.properties"); //Method 1
//is = Thread.currentThread().getContextClassLoader().getResourceAsStream(
       "com/rain/config/sys.properties"); //method 2
//is = ClassLoader.getSystemResourceAsStream("com/rain/config/sys. properties"); //

If method 3 is a configuration file, you can read the content into Properties through java.util.Properties.load(is), and pay attention to the encoding problem here. 
3. Use ResourceBundle 

    ResourceBundle bundle = ResourceBundle.getBoundle("com.rain.config.sys");

This usage is usually used to load the user's configuration file. For more detailed usage of ResourceBundle, please refer to other documents to 
summarize: there are 3 as follows Ways to load files 

    1. Absolute path ---> IO 
    2. Relative path ---> IO
                ---> ClassLoader
    3. Resource file ---> ResourceBundle

2. 

       |- JSP, HTML, Image and other files
        |- [WEB-INF]
              |- web.xml
              |- [lib] JAR files used by Web
                |- [classes] Class files

User programs are usually in the classes directory, if If you want to read the files in the classes directory, you can use ClassLoader. If you want to read other files, generally use ServletContext.getResource(). 
If you use the ServletContext.getResource(path) method, the path must start with "/", and the path is interpreted as Relative to the path of ContextRoot, the method of loading files here is different from ClassLoader, for example "/WEB-INF/web.xml", "/download /WebExAgent.rar"

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325899194&siteId=291194637