当前位置:网站首页>JVM (19) -- bytecode and class loading (4) -- talk about class loader again

JVM (19) -- bytecode and class loading (4) -- talk about class loader again

2022-07-07 05:24:00 leo_ messi94

1. summary

The class loader is JVM The premise of executing the class loading mechanism .

1.1 Classloader The role of :

Classloader yes Java Core components , be-all Class It's all by Classloader Loading ,Classloader Be responsible for bringing... Through various means Class The binary data stream of information is read in JVM Inside , Convert to a corresponding java.lang.Class Object instances . And then to Java Virtual machine to link 、 Initialization and other operations . therefore ,Classloader Throughout the loading phase , Can only affect the loading of classes , And not through Classloader To change the linking and initialization behavior of a class . As for whether it can run , By
Execution Engine decision .
 Insert picture description here

1.2 Class load classification : Explicitly load vs Implicitly load

class The methods of explicit and implicit loading of files refer to JVM load class File to memory mode .

  • Explicit loading refers to loading in code by calling Classloader load class object , If used directly Class. forName(name) or this. getClass().getClassloader().loadClass() load class object ( call forName Method )
  • Implicit loading is not directly invoked in code. ClassLoader Method loading class object , Instead, it is automatically loaded into memory through the virtual machine , When loading a class's class When you file , Of the class class The object of another class is referenced in the file , At this point, the extra referenced class will be passed through the JVM Automatically load into memory .(new The way )

In daily development, the above two methods are usually mixed

1.3 The necessity of class loader :

In general ,Java Developers don't need to explicitly use class loaders in their programs , But it is very important to understand the loading mechanism of class loader . From the following aspects :

  • Avoid problems in development java.lang.ClassNotFoundException Abnormal or java.lang.NoClassDefFoundError When abnormal , At sea . Only by understanding the loading mechanism of class loader can we quickly locate and solve problems according to the error exception log when exceptions occur
  • When you need to support dynamic loading of classes or need to encrypt and decrypt the compiled bytecode file , We need to deal with classloader .
  • Developers can write custom class loaders in their programs to redefine the loading rules of classes , In order to achieve some custom processing logic .

1.4 Namespace

1.4.1 What is the uniqueness of a class ?

For any class , It needs to be confirmed by the class loader that loads it and the class itself ]ava Uniqueness in virtual machines . Every class loader , All have a separate class namespace : Compare two classes for equality , It makes sense only if the two classes are loaded by the same classloader . otherwise , Even if the two classes originate from the same Class file , Loaded by the same virtual machine , As long as their classloaders are different , Then these two classes must not be equal

1.4.2 Namespace
  • Each class loader has its own namespace , The namespace consists of the loader and all classes loaded by the parent loader
  • In the same namespace , The full name of the class does not appear ( Include the package name of the class ) The same two classes
  • In different namespaces , It is possible that the full name of the class ( Include the package name of the class ) The same two classes

In large applications , We often use this feature , To run different versions of the same class .

1.4.3 Basic features of class loading mechanism

 Insert picture description here

2. Class loader classification

 Insert picture description here

  • In addition to the top-level boot loader , The rest of the class loaders should have their own “ Parent class ” loader
  • Different class loaders seem to be inherited , It's actually an inclusion relationship . In the lower loader , Contains a reference to the upper loader .

2.1 Start class loader ( Boot class loader , Bootstrap Classloader)

  • This class loads using C/C++ The realization of language , Nested in JVM Inside
  • It's used to load Java The core of the library ( JAVA HOME/jre/lib/rt.jar or sun.boot.class.path The content of the path ). For providing JVM The class you need
  • Not inherited from java.lang.ClassLoader, No parent loader .
  • For safety reasons , Bootstrap The boot class loader only loads packages named java、 javax、sun Class with equal beginning
  • Loading extension classes and application class loaders , And designated as their parent class loader .

 Insert picture description here Use -XX:+TraceclassLoading Parameters get

2.2 Extend the classloader (Extension ClassLoader)

  • Java Language writing , from sun.misc. Launcher$ExtClassloader Realization
  • Inherited from ClassLoader class
  • The parent loader is the boot loader
  • from java.ext,dirs Load the class library in the directory specified by the system property , Or from JDK Of the installation directory jre/lib/ext Load class library under subdirectory . If the user created JAR Put it in this directory , It will also be automatically loaded by the extension class loader .

 Insert picture description here

2.3 Application class loader ( system class loader ,AppClassloader)

  • java Language writing , from sun.misc. Launchers$AppClassloader Realization
  • Inherited from ClassLoader class
    The parent class loader is the extension class loader
    It's responsible for loading environment variables classpath Or system properties java.class.path Designated road
    The class loader in the class library application under path is the system class loader by default .
    It is the default parent loader for user-defined class loaders
    adopt Classloader Of getSystemClassLoader() Method to get the class plus
    Carrier

2.4 User defined class loader

  • stay Java In daily application development , Class loading is almost done by 3 Class loaders work with each other . When necessary , We can also customize the classloader , To customize how classes are loaded .
  • reflect Java One of the key factors of language's great vitality and charm is ,Java Developers can customize the class loader to realize the dynamic loading of class libraries. The loading source can be local JAR package , It can also be a remote resource on the network .
  • Through the class loader, you can achieve a very wonderful plug-in mechanism , There are numerous practical cases in this field . for example , The famous OSGI Component framework , Again Eclipse Plug in mechanism of . Class loaders provide a mechanism for applications to dynamically add new functions , This mechanism can be implemented without repackaging and publishing applications .
  • meanwhile , Custom loader can achieve application isolation , for example Tomcat, Spring And so on middleware and component framework have realized the custom loader inside , And separate different component modules through custom loader . This kind of mechanism is better than others C/C++ The program is so much better , I don't want to change it C/C++ The program can add new functions to it , It's almost impossible , Just one compatibility can stop all good ideas
  • Custom class loaders usually need to inherit from ClassLoader

3. ClassLoader The source code parsing

 Insert picture description here
In addition to the loader of the above virtual machine , Users can also customize their own class loaders .Java Abstract classes are provided java.lang.ClassLoader, All user-defined class loaders should inherit ClassLoader class .

3.1 ClassLoader Main methods

 Insert picture description here
 Insert picture description here
 Insert picture description here
 Insert picture description here

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    
    synchronized (getClassLoadingLock(name)) {
    
        // First, check if the class has already been loaded
        //  First , Judge whether the class with the same name has been loaded in the cache 
        Class<?> c = findLoadedClass(name);
        if (c == null) {
    
            long t0 = System.nanoTime();
            try {
    
            	//  Gets the parent loader of the current class loader 
                if (parent != null) {
    
                	//  If there is a parent loader, let the parent loader load 
                    c = parent.loadClass(name, false);
                } else {
    
                	// If the loader of the parent class is empty   It means recursion to bootStrapClassloader 了 
                    //bootStrapClassloader It's special. It can't pass get obtain 
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
    
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
    
                // If still not found, then invoke findClass in order
                // to find the class.
                // If bootstrapClassLoader  Still not loaded , Then recursion comes back , Try to load it yourself class
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
     //  Whether to perform parsing operation 
            resolveClass(c);
        }
        return c;
    }
}

protected Class<?> findClass(String name){
    
   //1.  According to the class name passed in name, Search for class files in a specific directory , hold .class File read into memory 
      ...
      
   //2.  call defineClass Convert the byte array into Class object 
   return defineClass(buf, off, len);
}

//  Parse the bytecode array into a Class object , use native Method realization 
protected final Class<?> defineClass(byte[] b, int off, int len){
    
   ...
}

3.2 ClassLoader Main subclasses of

 Insert picture description here
 Insert picture description here

3.3 Class.forName() And ClassLoader.loadClass()

 Insert picture description here

4. Parent delegation model

4.1 Definition and essence

Class loaders are used to load classes into Java In the virtual machine . from JDK1.2 Version start , The loading process of the class adopts the parental delegation mechanism , This kind of mechanism can better guarantee the safety Java Platform security .

4.1.1 Definition

If a class loader receives a request to load a class , It will not try to load this class by itself , Instead, the request task is delegated to the parent loader , Recursion in turn , If the parent loader can complete the class loading task , You're back . Only when the parent loader cannot complete this load task , Just load it yourself .

4.1.2 The essence

Specifies the order of class loading : Boot class loader loads first , If it doesn't load , Loaded by extension class loader , If it doesn't load yet , Will be loaded by system classloader or custom classloader .
 Insert picture description here

 Insert picture description here

4.2 Advantages and disadvantages of parental delegation mechanism

4.2.1 advantage :
  • Avoid duplicate loading of classes , Ensure global uniqueness of a class
    Java Class has a hierarchical relationship with priority along with its classloader , Through this level, we can avoid the repeated loading of classes , When the father has loaded the class , There is no need ClassLoader Load again
  • Protect program security , Prevention core API Be arbitrarily edited
4.2.2 Code support

The parental delegation mechanism is in java.lang,Classloader,loadClass( String, boolean) Interface . The logic of the interface is as follows :

  1. First, find out whether there is a target class in the cache of the current loader , If there is , Go straight back to .
  2. Determine whether the parent loader of the current loader is empty , If it's not empty , Call parent.loadclass(nane, false) Interface to load .
  3. conversely , If the parent of the current loader is empty , Call findbootstrapclassornul(name) Interface , Let the bootloader load .
  4. If you pass the above 3 All paths failed to load , Call findclass(name) Interface to load . The interface will eventually call java.lang.ClassLoader Interface definedClass Series of native Interface load target Java class .

The model of parental delegation is hidden in this section 2 And the 3 In step .

4.2.3 give an example

Suppose that the current load is java.lang. objecti This class , Obviously , This category belongs to JDK The core experience can no longer be a core class , So it must only be loaded by the bootloader . When JVM Ready to load javalang.Object when ,JVM By default, the system classloader will be used to load , Follow the above rules , In the 1 Step: the system class cannot be found from its cache , So we go to the second 2 Because the parent loader of the slave system class loader is an extension class loader , So the extended class loader continues to repeat from the first step . Because the extension class adds
You can't find this in the cache of the loader , So go to step two . The parent loader of the extension class is null, So the system calls findClass( String), Finally, it is loaded by bootloader .

4.2.4 reflection

If overridden in a custom class loader java.lang.Classloader.loadClass( string) or java.lang.Classloader.loadClass( String, boolean) Method , Remove the parental appointment mechanism , Just keep the above one 4 Step 2 1 Step and step 4 Step , Is it possible to load the core class library ?

It's not going to work ! because JDK It also provides a layer of protection mechanism for the core class library . Whether it's a custom class loader , Or system class loader or extended class loader , Must be called in the end java.ang.Classloader. definedClass(String,byte],int,int,Protectiondomain) Method , And the method does predefinedClass() Interface , The interface provides the JDK Protection of core class library .

4.2.5 The disadvantages of the parental entrustment model

The delegate process of checking whether a class is loaded is one-way , This way is relatively clear in structure , Make each Classloaderl Our responsibilities are very clear , But there is also a problem , It's the top floor classloader Unable to access underlying classloader The class loaded .

Usually , The classes in the bootloader are the core classes of the system , Including some important system interfaces , In the application class loader , For application class . Follow this pattern , There is no problem for application class to access system class , But there will be problems when the system class accesses the application class . For example, an interface is provided in the system class , The interface needs to be implemented in the application class , The interface also binds a factory method , An instance used to create the interface , The interface and factory methods are in the boot loader . At this time , The factory method cannot create an application instance loaded by the application class loader .

4.2.6 Conclusion

because Java The virtual machine specification does not explicitly require that the loading mechanism of class loaders must use the parental delegation model , It is only suggested to adopt this method .
For example Tomcat in , The loading mechanism adopted by the class loader is different from the traditional two-system delegation model , When the default class loader receives a class load task , First, it loads itself , When it fails to load ,オ It will delegate the loading task of the class to its superclass loader to execute , It's also Servlet A method of standard recommendation

4.3 Break the parental delegation mechanism

The parental delegation model is not a model with mandatory constraints , It is Java The implementation of class loader recommended by designers to developers .

stay Java Most of the world's classloaders follow this model , But there are exceptions , until Java Until modularity came into being , The model of parent delegation mainly appeared 3 The second is larger “ Be destroyed ” The situation of .

4.3.1 The first time to destroy the mechanism of parents' appointment

The first time a parent delegation model “ Be destroyed ” In fact, it happened before the emergence of the parental delegation model, that is JDK1.2 Before it came out “ ancient ” Time .

Because the parent delegation model is in JDK1.2 Then it was introduced , But the concept of class loaders and abstract classes java.lang.Classloaderl It's in Java In the first version of , Facing the existing user-defined class loader code ,Java Designers have to make some compromises when introducing the parental delegation model , In order to be compatible with the existing code , There is no longer a technical means to avoid lloadClass() The possibility of being covered by subclasses , Only in JDK1.2 After that java.lang.ClassLoader Add a new protected Method findclass(), And guide the user to rewrite this method as much as possible when loading the class logic , Not in loadClass() Code in . We have analyzed in the last section loadclass() Method , The specific logic of parental appointment is realized here , according to loadClass() The logic of the method , If the parent class fails to load , Will automatically call your own findclass() Method to complete the load , This does not affect users to load classes according to their own wishes , It can also ensure that the newly written class loader is in line with the parental delegation rules .

4.3.2 For the second time, the mechanism of parental appointment was destroyed : Thread context class loader

The second time of the parent delegation model “ Be destroyed ” It is due to the defects of the model itself , Parent delegation solves the problem of consistency of basic types in the cooperation of various class loaders ( The more basic class is loaded by the higher loader ), The basis type is called “ Basics ”, Because they are always inherited by user code 、 Called API There is , But programming often does not have absolutely invariable perfect rules , If there is an underlying type, it will call back to the user's code , So what do we do?

It's not impossible , A typical example is JNDI service ,JNDI Now it is Java Standard services , Its code is loaded by the boot loader ( stay JDK1.3 To join in rt jar Of ), It must belong to Java It's a very basic type . but JNDI The purpose of existence is to search and centralize the management of resources , It needs to call the classpath Under the JNDI Service provider interface (Service Provider Interface,SPI) Code for , Now comes the question , It's impossible to start a class loader 、 Loading the code , So what do we do? ?(SPT: stay Java In the platform , The core class rt,jar Provide external services in 、 Interfaces that can be implemented by the application layer are called SPT)

To solve this dilemma ,]ava Our design team had to introduce a less elegant design : Thread context class loader ( Thread ContextC1 assloader). This class loader can be used through java.lang. Thread Class setcontextclassloader() Method to set , If the thread is not set when it is created , It will inherit a... From the parent thread , If it has not been set in the global scope of the application , Then this class loader is the application class loader by default .

With thread context class loader , The program can do some “ Fraud ” It's something .JNDI The service uses this thread context class loader to load the required SPI Service code , This is the behavior of the parent class loader asking the child class loader to complete the class loading , This behavior actually opens up the hierarchy of the dual system delegation model to reverse the use of class loaders , Has violated the general principles of the parental delegation model , But it's also a helpless thing .Java It's about SPI The loading of is basically done in this way , for example JNDI、JDBC、JCE、JAXB and JBI etc. . however , When SPI When you have more than one service provider , The code can only be hard coded according to the type of specific provider , In order to eliminate this very inelegant implementation , stay JDK6 when ,JDK It provides a relatively reasonable solution .
 Insert picture description here
The default context loader is the application class loader , In this way, the loader is the intermediary , So that the code in the boot loader can also access the classes in the application loader

4.3.3 For the third time, the mechanism of appointing parents was destroyed :

The third time the parent delegation model “ Be destroyed ” It is due to the user's pursuit of program dynamics . Such as : Code hot swap ( Hot Swap)、 Module hot deployment ( Hot Deployment) etc.

IBM Company led JSR-291( namely OSGI R4.2) The key to realize modular hot deployment is the implementation of its custom classloader mechanism , Every program module (OSGi called Bundle) All have their own classloader , When you need to replace one Bundle when , Just put Bundle Replace with the same kind of loader to realize the hot replacement of code . stay OSGi In the environment , Class loaders are no longer the tree structure recommended by the parental delegation model , But further developed into more complex Network structure .

When a class load request is received ,OSGi Class search will be done in the following order :

  1. Will be with java.* Initial class , Delegate to parent loader to load
  2. otherwise , The class in the list will be delegated , Delegate to parent loader to load .
  3. otherwise , take Import Classes in the list , Delegate to Export This class of Bundle The class loader of the .
  4. otherwise , Find the current Bundle Of ClassPath, Use your own classloader to load .
  5. otherwise , Find out if the class is in its own Fragment Bundle in , If in , To Fragment Bundle Class loader loading .
  6. otherwise , lookup Dynamic Import List Bundle, Delegate to the corresponding Bundle Class loader loading
  7. otherwise , Class lookup failed .

explain : Only the first two points are still consistent with the principle of parental delegation model , The rest of the class lookups are done in a flat classloader

Summary :
here , We used “ Be destroyed ” This word is used to describe the above behaviors that do not conform to the principles of the parental delegation model , But here “ Be destroyed ” It's not necessarily derogatory . As long as there is a clear purpose and a good reason , Breaking through the old principles is undoubtedly an innovation .

just as :OSGi The design of class loader in is not in line with the traditional parental delegation class loader architecture , And there are still many controversies in the industry about the extra high complexity brought by its hot deployment , However, technical personnel who have an understanding of this aspect can basically reach a consensus , Think OSGi The application of class loader in is worth learning , I totally understand OSGi The implementation of the , Even if you have mastered the essence of class loader .

4.4 Implementation of hot replacement

 Insert picture description here
 Insert picture description here

5. Sandbox security mechanism

 Insert picture description here
 Insert picture description here
 Insert picture description here
 Insert picture description here
 Insert picture description here

6. Loaders for custom classes

 Insert picture description here
 Insert picture description here

6.1 Realization

 Insert picture description here
 Insert picture description here
The code is slightly ...

7. jdk9 New characteristics

 Insert picture description here
 Insert picture description here
 Insert picture description here
Changes in parental delegation :
 Insert picture description here

原网站

版权声明
本文为[leo_ messi94]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207062326465961.html