Isolation in the Java type load system
Author: Shengge Xin
About the Author
Sheng Ge, Software Engineer, you can contact him through Shenggexin@topWaver.com.
text:
The problem of searching and loading in Java is always in front of the Java program from time to time, this is not a shameful thing, I believe that there is no java programmer has not encountered ClassNotException, so don't see yourself. Such a mistake felt unnatural, but if there was an abnormality behind the classNotFoundException, I thought you should learn about the system of Java's class load, while in order to perform the following about the isolation Sexual discussion, let's briefly introduce the architecture of the type load.
1. Java type loading architecture
The process of loading classes is very simple: lookup class in position, and load the bytecode of the found Java class into memory to generate the corresponding Class object. Java's class loader is specifically used to implement such a process, and JVM does not have a class loader. In fact, if you like, you can let JVM have countless loaders, of course, in addition to testing JVM, I think There is no other use. You should have discovered such a problem, and the type-loaded loader itself is also a class, it also needs to be loaded into memory, then who these loaders are loaded, have you always have a root? That's true, there is a root. It is the Bootstrap ClassLoader who is not seen in the army. Why is it not seen that it is not seen by the Dragon, because you can't grasp even a little tail that is it in the Java code. You can always feel its existence, because all class libraries required by Java's running environment are loaded, and it is a program written by C , which can be run independently, can be said to be the starting point of JVM, Great. After Bootstrap Complete its task, an AppClassLoader generates an AppClassLoader (actually previously using the extended type loader EXTCLASSLOADER, which is used to load the class in the Java running environment extension), this class loader is what we often use. You can call ClassLoader.getsystemClassLoader () to get it, we assume that there is no use of the class loader related operation settings or custom new type loadware, then all Java class doing all Java class will be loaded by it, it is worthy of respect. . AppClassLoader Finding the area of the class is the unfolded classpath, but also the threshold that beginners must cross, there is a feeling of flashing, and we are named the type path class loader according to its class lookup. Still a previous case, when new classes appear in Java, AppClassLoad is first passed to its parent class type loader, which is EXTION CLASSLOADER, asking it to load this class, if it can, the appclassloader does not do this Live, the same EXTION CLASSLOADER is loaded, and it will ask its parent class loader. We can see that the type loader is actually a tree-shaped structural diagram. Each type loader has its own father, when the loader is loaded, you always let your parent class loader load (how respectful elders If the parent class loader cannot load the class, you will be loaded, if it is also loaded, then you can't afford it, it will shout: Exception, Class Not Found. It is necessary to mention it, and the failure of loading classes directly using the classpath loader is NoclassdefoundException exception. If you use a custom class loader loadClass method or ClassLoad's FindSystemClass method to load classes, if you don't deliberately change, then throws ClassNotFoundException. We conclude the discussion above:
1. The architecture of the JVM class load can be considered as a tree structure.
2. The parent class loader is prioritized. Loads in the case where the parent class loader is loaded, and the ClassNotFoundException or NoclassDefoundError is thrown if all load failed.
So what is our class is loaded?
2. How to be loaded
In Java2, how JVM is loaded, can be divided into two types, one is implicitly loaded, a fashion explicit class load.
2.1 Implicit class loading
Implicit class load is the most common way in the encoding:
A b = new a ();
If the program runs to this code, there is no Class A, then JVM requests the typewinder to load the current class to load classes. The problem is coming, I make the code a little bit, but there is still no difficulty, please think about JVM to load order:
Package test; public class a {public void static main (string args []) {b = new b ();}}
Class B {C C;}
Class C {}
Justice the answer, the order of the layers is A-> B, and class C will not be subjected to JVM, don't be surprised, think about it, this is not what we need. Let's take a closer understanding of the JVM loading order. When running the A class using the Java A command, JVM will first require the Class A, but only load A, which does not load other classes (Class B) appearing in A, then it will Call the main function until the statement b = new b () is run, the JVM finds that the Class B program must continue to run, so the class path-loader will load Class B, although we can see that there is Class C declaration, but not actually executing statements, so don't load C class, that is, JVM is performing a valid execution statement in runtime to decide whether to load new categories, so that you can load as few classes as possible. Little and compiled classes are different.
2.2 Explicit class loading
There are a lot of load methods that are displayed, and we are all loaded with Test.a as an example.
Use the CLASS class forname. It can specify a loader or a loader loaded with the current class. E.g:
Class.Forname ("Test.a"); its effect and class.forname ("Test.a", true, this.getClass (). GetClassLoader ()); is the same.
Load loading using class path classes.
ClassLoader.getsystemClassLoader (). LoadingClass ("Test.a");
Loading using the class loader used in the current process context, which is often used by systems with complex type loading architectures.
Thread.currentthread (). GetContextClassLoader (). Loadingclass ("test.a")
Load the class with a custom class loading
public class MyClassLoader extends URLClassLoader {public MyClassLoader () {super (new URL [0]);}} MyClassLoader myClassLoader = new MyClassLoader (); myClassLoader.loadClass ( "test.A");
MyClassLoader inherits the URLClassLoader class. This is the typeloader in the JDK core package. When the parent class loader is not specified, the class path type loader is its parent class loader, and myclassloader does not increase the range of findings. Therefore, it has the same effect as the class path loader.
We already know that the Java's class loader architecture is a tree, and multiple type loaders can specify the same class loader as their own parent class, each subclass loader is a branch of the tree structure, of course they can be There is a sub-loader type loader, and the class loader can also have no parent class loader. At this time, the Bootstrap class load will be used as its implicit parent class. In fact, the Bootstrap class loader is a ancestor of all type loaders, too The root of the tree structure. This tree architecture, as well as the parent class loader, providing a convenience of writing a custom class-loaded loader, while allowing the program to be loaded in the way we want. For example, a class loader architecture diagram of a program is as follows: Figure 2: Structure of a class-loader loader
Explain that the above figure, ClassLoadera is a custom class loader, its parent class loader is a class-loader, which has two subclass loaders ClassLoadraa and ClassLadeRab, ClassLoaderB is another class loader used by the program, it There is no parent class loader, but there is a subclass loader ClassLoaderbb. You may say, see how ghosts, how can my programs use such a complex class loader structure. In order to carry out the following discussion, it is temporarily buning.
3. Strange isolation
We are not difficult to find that the type-loaders AA and AB, AB, AA and B, etc. in Figure 2 are located under different branches. They have no father and child relationship between them. I don't know how to define this relationship, just call them. Different branches. Two type-loading lockers located at different branches have isolation, which makes two examples of Class classes in memory in memory, respectively. Because the class with the isolated type-loaded loader load does not share memory space, it makes it possible to use a task that is unlikely to complete with a class loader. For example, the static variables of the class may have multiple values at the same time (although it does not seem to work. Because even if it is the same static variable that is loaded, they will also be saved in different memory spaces, alternatively, for example, some packages, but do not want to be used by other packages, very simple, write self Defined class loading. This isolation of the type loader has been well applying in many large software applications and service procedures. Below is an example of the same class static variable as different values.
Package test; public class a {public static void main (string [] args) {Try {// Define two type loader MyclassLoader AA = new myclassloader (); myclassloader bb = new myclassloader ();
// Load Testb.b class class Clazz = aa.loadclass ("Testb. B"); constructor constructor = CLAZZ.GETCONSTRUCTOR (new class [] {integer.class}); object object = constructor.newinstance (new object [] {new integer (1)}); method method = Clazz.GetDeclaredMethod ("Printb", New class [0]);
@ Bb loaded by class loader testb.B class Class clazz2 = bb.loadClass ( "testb B."); Constructor constructor2 = clazz2.getConstructor (new Class [] {Integer.class}); Object object2 = constructor2.newInstance (New Object [] {new integer (2)}); method method2 = CLAZZ2.GETDECLAREDMETHOD ("PrintB", new class [0]); // Displays the value of the static variable in Test.b method Method.invoke (Object, New Object [0]); method2.invoke (Object2, new object [0]);} catch (exception e) {E.PrintStackTrace ();}}}
// Class B must be located within the lookup of MyClassLoader, / / / / should not be in the lookup of MyClassLoad's parental loader. Package testb; public class b {static int b;
PUBLIC B (Integer Testb) {b = testb.intvalue ();
Public void printb () {system.out.print ("My Static Field B IS", B);}}
Public class myclassloader extends urlclassloader {private static file file = new file ("c: // classes"); // This path stores Class B, but there is no Class A
Public myclassloader () {super (getURL ());
Public static url [] getURL () {Try {Return new url [] {file.tourl ()};} catch (mALFORMEDURLEXCEPTION E) {Return New URL [0];}}}
The result of the program is:
My Static Field B IS 1my Static Field B IS 2
The results of the program are very interesting. From the perspective of the programmer, we can even see the class loaders that are not in the same branch as a different Java virtual machine, as they do not feel that each other's existence. The program should be very careful when using the architecture with branch-loaded architecture, clarify each type of loader's class lookup, try to avoid the same name of the same name in the class lookup of the parental loader and subclass loader. (Including the name and class name), the following example is used to illustrate the problem that this situation may bring.
Assume that there is the same name but different versions of interface A,
Version 1: Package test; intermute {public string getversion ();} version 2: package test; intermne {public string getname ();}
Interface A Double Version:
Version implements package test 1 the; public class Same1Impl implements Same {public String getVersion () {return "A version 1";}} achieved public class version 2 Same 2Impl implements Same {public String getName () {return "A version 2 "}} We still use the class loader structure of Figure 2, first of all, the SAME and SAME of the version 1 is first set to the package Same1.jar, and the Same and Same of the Same and Same of the version 2 are set to the package SAME2. JAR. Now, do this, put the Same1.jar into the class loader ClassLoadera class lookup, put the Same2.jar into the class lookup range of the type of ClassLoaderab. When you are so exciting, this seems a correct program.
In fact, this error is caused by the mechanism of the parent type carrier, when the class loader ClassLoaderAb is loaded when the Same2Impl class is loaded, and the parent class loader is loaded, the parent class loader is discovered by the prescribed request. The Test.same interface of the version 1 is in the hands of the buzz, but I can't think of the test.same of Same2Impl is the version 2 Test.same, and the things will be imagined, and the abnormality is thrown.
We are difficult to blame the mechanism for distinguishing between Java, if you use a complicated class loader architecture, you should pay special attention when a plurality of versions of a package or class appears.
Mastering and flexibly use Java's class-loaded architecture, the system design, program realization, and programs have been debugged, have considerable help. I hope that the above content can help you.