Interviewer: Why does the tomcat class loader violate the parental delegation model?

Release: 2023-08-17 14:36:38
forward
1089 people have browsed it

A few days ago, a friend was asked about class loading during an interview. He answered questions related to class loading in a regular way, and he could handle it as long as he memorized the interview questions a little.

But if you ask deeper, just a little deeper, you can cool a large number of people.

For example: Why does the tomcat class loader violate the parental delegation model?

In order to prevent you from encountering this kind of situation during the interview, this article will arrange this matter.

We divide it into 4 parts to discuss:

  1. What is the class loading mechanism?
  2. What is the Parental Appointment Model?
  3. How to break the parental delegation model?
  4. How is the Tomcat class loader designed?

I think, before studying tomcat class loading, we should review or consolidate the java default class loader. When I first started learning JVM, I was confused about the class loading mechanism, so I would like to take this opportunity to share it with you.

1. What is the class loading mechanism?

The conversion of the code compilation result from local machine code to bytecode is a small step in the storage format, but a big step in the development of programming languages.

The Java virtual machine loads the data describing the class from the Class file into the memory, verifies the data, converts, parses and initializes it, and finally forms a Java type that can be used directly by the virtual machine. This is the function of the virtual machine. Class loading mechanism.

The virtual machine design team implemented the action of "obtaining a binary byte stream describing this class through the fully qualified name of a class" in the class loading phase outside the Java virtual machine, so that the application Decide for yourself how to get the classes you need. The code module that implements this action is called a "class loader".

The relationship between classes and class loaders

Although the class loader is only used to implement the loading action of the class, its role in the Java program is far from limited to the class loading stage. For any class, the class loader that loads it and the class itself need to establish its uniqueness in the Java virtual machine. Each class loader has an independent class namespace.

This sentence can be expressed in a more popular way: comparing whether two classes are "equal" only makes sense if the two classes are loaded by the same class loader. Otherwise, even if this Two classes come from the same Class file and are loaded by the same virtual machine. As long as the class loaders that load them are different, the two classes must not be equal.

2. What is the parent delegation model

1. From the perspective of the Java virtual machine, there are only two different class loaders: one is the boot class loader (Bootstrap ClassLoader) , this class loader is implemented in C language (HotSpot only) and is part of the virtual machine itself; the other is all other class loaders, which are implemented in Java language and are independent of the virtual machine, and All inherit from the abstract class java.lang.ClassLoader.

2. From the perspective of Java developers, class loading can be divided into more details. Most Java programmers The following three system-provided class loaders will be used:

  • Bootstrap ClassLoader: This class loader will be stored in the JAVA_HOME/lib directory or in the path specified by the -Xbootclasspath parameter. And it is recognized by the virtual machine (it is only recognized by the file name, such as rt.jar. Class libraries with inconsistent names will not be overloaded even if they are placed in the lib directory).
  • Extension ClassLoader: This class loader is implemented by sun.misc.Launcher$ExtClassLoader, which is responsible for All class libraries in the JAVA_HOME/lib/ext directory, or in the path specified by the java.ext.dirs system variable. Developers can use the extension class loader directly.
  • Application ClassLoader: This class loader is implemented by sun.misc.Launcher$AppClassLoader. Since this class loader is the return value of the getSystemClassLoader method in ClassLoader, it also becomes the system class loader. It is responsible for loading the class library specified on the user class path (ClassPath). Developers can use this class loader directly. If the application does not define its own class loader, this is usually the default class loader in the program.

The relationship between these class loaders is generally as shown in the figure below:

Interviewer: Why does the tomcat class loader violate the parental delegation model?
Picture

In the picture The relationship between each class loader is called Parent Delegation Model (Parents Dlegation Mode) of the class loader. The parent delegation model requires that in addition to the top-level startup class loader, all other class loaders should be loaded by their own parent class loaders. The parent-child relationship between class loaders here is generally not realized by inheritance, but by inheritance. They all use composition relationships to reuse the code of the parent loader.

Note: During the interview, the interviewer may also ask which directory the corresponding class loader loads.

The parent delegation model of the class loader was introduced during JDK1.2 and is widely used in all subsequent Java programs, but it is not a mandatory constraint model, but a Java design A class loader implementation method recommended to developers.

The working process of the parent delegation model is: if a class loader receives a class loading request, it will not try to load the class itself first, but delegates the request to the parent class loader to complete. This is true for every level of class loader, so all loading requests should eventually be sent to the top-level startup class loader. Only when the parent loader feedbacks that it cannot complete the request (the required one is not found in its search scope) class), the subloader will try to load it by itself.

Why do you do that?

If the parent delegation model is not used and each class loader loads it by itself, if the user writes a class called java.lang.Object and puts it in the ClassPath of the program, the system will When multiple different Object classes appear, the most basic behavior in the Java type system cannot be guaranteed. Applications will also become a mess.

How is the parent delegation model implemented?

Very simple: all the code is in the loadClass method in java.lang.ClassLoader, the code is as follows:

Interviewer: Why does the tomcat class loader violate the parental delegation model?
Picture

The logic is clear and easy to understand: first check whether it has been loaded. If not, call the loadClass method of the parent loader. If the parent loader is empty, the startup class loader will be used as the parent by default. Loader. If the parent class fails to load, throw a ClassNotFoundException exception and then call its own findClass method to load it.

3. How to break the parental delegation model?

We just said that the parent delegation model is not a mandatory constraint model, but a suggested class loader implementation. Most class loaders in the Java world follow this model, but there are exceptions. So far, the parental delegation model has been "broken" on a large scale three times.

The first time: before the emergence of the parental delegation model-----that is, before the release of JDK1.2.

The second time: It was caused by the flaws of the model itself. We say that the parent delegation model well solves the problem of unifying the base classes of each class loader (the more basic classes are loaded by the upper-level loader). The reason why the base class is called "basic" is Because they are always used as APIs called by user code, but there is no guarantee. What if the base class calls user code?

This is not impossible. A typical example is the JNDI service. JNDI is now a standard service in Java. Its code is loaded by the startup class loader (rt.jar that was put in JDK1.3), but it needs to be called and implemented by an independent vendor. And deploy the JNDI interface provider (SPI, Service Provider Interface) code under the ClassPath of the application, but it is impossible for the startup class loader to "know" these codes. Because these classes are not in rt.jar, but they need to be loaded to start the class loader. How to do it?

In order to solve this problem, the Java design team had to introduce a less elegant design: Thread Context ClassLoader. This class loader can be set through the setContextClassLoader method of the java.lang.Thread class. If it has not been set when the thread is created, it will inherit one from the parent thread. If not set too much in the global scope of the application, then this class loader will default to the application class loader.

Hey, with the thread context loader, the JNDI service uses this thread context loader to load the required SPI code, that is, the parent class loader requests the child class loader to complete the class loading action. This This behavior actually opens up the hierarchy of the parent delegation model to reversely use the class loader, which actually violates the general principles of the parent delegation model. But there is nothing you can do about it. All loading actions involving SPI in Java basically use this method. For example JNDI, JDBC, JCE, JAXB, JBI, etc.

The third time: In order to achieve hot-swap, hot-deployment, and modularization, which means adding a function or subtracting a function without restarting, you only need to replace the module together with the class loader. This achieves hot replacement of code.

The book also says:

There is basically a consensus in Java programs: OSGI’s use of class loaders is worth learning. Once you understand the implementation of OSGI, you can It can be regarded as mastering the essence of class loader.

Awesome! ! !

Now, we have basically understood the working principle of Java default class loading and also know the parent delegation model. Having said so much, I almost forgot about our tomcat. Our topic is why does the Tomcat loader violate the parental delegation model?

Let’s talk about our tomcat class loader.

4. How is Tomcat’s class loader designed?

First of all, let’s ask a question:

Is it okay if Tomcat uses the default class loading mechanism?

Let’s think about it: Tomcat is a web container, so what problems does it need to solve:

  • A web container may need to deploy two applications, and different applications may rely on the same Different versions of a third-party class library cannot require only one copy of the same class library on the same server. Therefore, it is necessary to ensure that the class libraries of each application are independent and isolated from each other.
  • The same class library and the same version deployed in the same web container can be shared. Otherwise, if the server has 10 applications, then 10 copies of the same class library must be loaded into the virtual machine, which is nonsense.
  • The web container also has its own dependent class libraries, which cannot be confused with the application's class libraries. For security reasons, the container's class library should be isolated from the program's class library.
  • The web container must support the modification of jsp. We know that the jsp file must eventually be compiled into a class file before it can be run in a virtual machine. However, it is common for jsp to be modified after the program is run. , otherwise what use would you have? Therefore, the web container needs to support jsp modification without restarting.

Let’s look at our question again: Is it okay if Tomcat uses the default class loading mechanism?

The answer is no. Why? Let’s look at the first problem. If you use the default class loader mechanism, you cannot load two different versions of the same class library. The default accumulator only cares about your fully qualified class no matter what version you have. name, and only one copy.

The second question is that the default class loader can be implemented because its responsibility is to ensure uniqueness. The third question is the same as the first question. Let's look at the fourth question again. We think how do we implement hot modification of jsp files (the name given by the poster). The jsp file is actually a class file. So if it is modified, but the class name is still the same, the class loader will directly If the jsp already exists in the method area is retrieved, the modified jsp will not be reloaded.

So what should we do? We can directly uninstall the class loader of this jsp file, so you should have thought that each jsp file corresponds to a unique class loader. When a jsp file is modified, the jsp class loader is directly unloaded. Re-create the class loader and reload the jsp file.

How does Tomcat implement its own unique class loading mechanism?

So, how does Tomcat implement it? The awesome Tomcat team has already designed it. Let’s take a look at their design drawings:

Interviewer: Why does the tomcat class loader violate the parental delegation model?
Picture

We see that the first three class loadings are consistent with the default ones. CommonClassLoader, CatalinaClassLoader, SharedClassLoader and WebappClassLoader are Tomcat’s own class loaders. They load /common/*, /server/*, /shared/* respectively (after tomcat 6, they have been merged into the lib directory in the root directory ) and the Java class library in /WebApp/WEB-INF/*. There are usually multiple instances of the WebApp class loader and the Jsp class loader. Each Web application corresponds to a WebApp class loader, and each JSP file corresponds to a Jsp class loader.

  • commonLoader: Tomcat’s most basic class loader. The classes in the loading path can be accessed by the Tomcat container itself and each Webapp;
  • catalinaLoader: Tomcat container private class loader, the classes in the loading path are not visible to the Webapp;
  • sharedLoader : Class loader shared by each Webapp. The classes in the loading path are visible to all Webapps, but not visible to the Tomcat container;
  • WebappClassLoader: Private to each Webapp Class loader, the classes in the loading path are only visible to the current Webapp;

It can be seen from the delegation relationship in the figure:

CommonClassLoader can load all classes It can be used by Catalina ClassLoader and SharedClassLoader, thus realizing the sharing of public class libraries, while the classes that CatalinaClassLoader and Shared ClassLoader can load are isolated from each other.

WebAppClassLoader can use the classes loaded by SharedClassLoader, but each WebAppClassLoader instance is isolated from each other.

The loading scope of JasperLoader is only the .Class file compiled by this JSP file. The purpose of its appearance is to be discarded: when the Web container detects that the JSP file has been modified, it will replace the current An instance of JasperLoader, and create a new Jsp class loader to implement the HotSwap function of the JSP file.

Okay, so far, we already know why tomcat is designed this way and how it is designed. So, does tomcat violate the parent delegation model recommended by Java? The answer is: violated.

We said before:

The parent delegation model requires that in addition to the top-level startup class loader, the rest of the class loaders should be loaded by their own parent class The server is loaded.

Obviously, tomcat is not implemented in this way. In order to achieve isolation, tomcat does not comply with this agreement. Each webappClassLoader loads the class file in its own directory and will not pass it to the parent class loader.

We extend a question: What should we do if tomcat's Common ClassLoader wants to load classes in WebApp ClassLoader? After reading the previous content about destroying the parent delegation model, we have a clear idea. We can use the thread context class loader to implement it. Using the thread context loader, the parent class loader can request the child class loader to complete the class loading action. .

Isn’t it awesome?

Summary

Okay, finally, we understand why Tomcat violates the parent delegation model, and we also know how tomcat's class loader is designed. By the way, I reviewed Java's default class loader mechanism, and also learned how to destroy Java's class loading mechanism. This time the harvest is not small! ! !

The above is the detailed content of Interviewer: Why does the tomcat class loader violate the parental delegation model?. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:Java后端技术全栈
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template