Whether you’re discussing technical issues with colleagues, classmates, supervisors, peers, or interviewers, it’s easy to get caught up in a big JVM argument. To help you stand out from a big fight, I’ve been thinking a lot lately about how to make the points as easy to understand and remember as possible. Thus began the writing of this series of articles. In order for the JVM knowledge to form a system, Arthinking will write and organize a series of topics that depict the knowledge as graphically as possible, and eventually tie it all together into a graph. Continue to update, you are welcome to read. Have any strewn at random place also ask you to help correct, thank you!

Takeaway:

  1. How is a class loader created?
  2. What is the parent delegate mechanism? Why do we have this mechanism?
  3. Are Class instances and Class loaders in the Java Heap or in the method area?

Class loader: It is possible to obtain a binary byte stream describing a class by its fully qualified name. The code module that implements this action is called the classloader.

All kinds of interesting and powerful features can be implemented with custom class loaders: OSGi, hot deployment, code encryption, and more.

1. The loading process of class loader

The loading flow of the class loader is shown above.

Here is a brief description:

1.1. Start the class loader

** start the class loader: ** when the system starts, it first loads the jar packages in the <JAVA_HOME>/lib directory, or the jar packages in the path specified by the -xbootclasspath parameter and recognized by the vm through the C++ class loader. Load the related Class into the method area.

This step loads the key class: sun.misc.Launcher. This class contains two static inner classes:

  • ExtClassLoader: an internal class that extends the class loader, as described below;
  • AppClassLoader: An internal class of the application class loader, described below

You can decompile the rt.jar file to see the detailed code:

After loading the Launcher class, the class is initialized. During initialization, ExtClassLoader and AppClassLoader are created. The source code is as follows:

public Launcher(a) {
    ExtClassLoader extClassLoader;
    try {
      extClassLoader = ExtClassLoader.getExtClassLoader();
    } catch (IOException iOException) {
      throw new InternalError("Could not create extension class loader", iOException);
    }
    try {
      this.loader = AppClassLoader.getAppClassLoader(extClassLoader);
    } catch (IOException iOException) {
      throw new InternalError("Could not create application class loader", iOException);
    }
    Thread.currentThread().setContextClassLoader(this.loader); .Copy the code

Due to start the class loaders are implemented by c + +, so is not access inside the Java code to start the class loader,. If you try to through the String class. GetClassLoader () to obtain the references to classes, will return null;

Question:

  1. Who loads the launcher class loader, extension class loader, and application class loader?

    1. The startup class loader is an internal implementation of the JVM that is created by the JVM after the JVM has allocated memory
    2. Extension class loaders and application class loaders are loaded by the launcher class loaders;
  2. Say what the following code outputs:

 public static void main(String[] args) {
     System.out.println("Loader that loads the current class :" + TestClassLoader.class.getClassLoader());
        System.out.println("Loader for loading the application class loader"
                         + TestClassLoader.class.getClassLoader().getClass().getClassLoader());
        System.out.println("Start class loader for the String class" + String.class.getClassLoader());
   }
Copy the code

1.2. Extend class loaders

As shown above, the extension classloader is responsible for loading classes in the <JAVA_HOME>/lib/ext directory or in the path specified by the java.ext.dirs system variable.

1.3 application class loader

A reference class loader loads a class library specified under the user’s classpath. This class loader is the default class loader if the application has not customized its own.

The reference class loader, also known as the system class loader, can be obtained by using the getSystemClassLoader method.

Note that after the class is loaded into the method area through the above three classloaders, there should be a separate store of class information in the method area. The same class file loaded by different class loaders is not equal.

Class loaders’ parent delegate mechanism

2.1. Principle of parental delegation mechanism

The parent delegate model was introduced after JDK1.2 and is widely used. It is not a mandatory constraint model, but a kind of loader implementation recommended by Java designers to developers. We can also override the corresponding way to implement our own loading model.

The parent delegate mechanism for class loaders is as follows:

In other words:

  • When a classloader receives a classloading request, it does not immediately try to load the class itself. Instead, it delegates the request to the parent loader.
  • If the parent loader does not exist, try to determine if it has been loaded by the start class loader.
  • If it is not, try to load it yourself.

Question:

  1. Why is there such a complicated parental delegation mechanism?
    1. Without this mechanism, we could tamper with the classes needed to start the classloader, for example, by writing our ownjava.lang.ObjectUsing your own class loader to load, you would have multiple Object classes in the system, and the most basic behavior of the Java type system would not be guaranteed.

2.2. Process of parent delegation mechanism

What is the default parent delegate process in the JDK? Let’s take a look at the code, the following is a Java lang. This. LoadClass () method of implementation:

    protectedClass<? > loadClass(String name,boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loadedClass<? > c = findLoadedClass(name);if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if(parent ! =null) {
                        c = parent.loadClass(name, false);
                    } else{ 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.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); }}if (resolve) {
                resolveClass(c);
            }
            returnc; }}Copy the code

Into a flow chart, that is:

So, you always try to get the parent class loader to load first, then determine if the boot class loader is already loaded, and then try to load from the current class loader. The conversion to a clearer model is as follows:

The parental delegation model has the following characteristics:

  • Visibility Principle:
    • Application classloaders can read classes loaded by extension classloaders and start classloaders.
    • The extension Class loader can read classes loaded by the launcher Class loader;
  • Uniqueness:
    • Classes are unique; there are no duplicate classes;

2.3. Class loaders and Class instances

The launcher class loader, the extension class loader, and the application class loader each manage a block in their own method section.

As we know from the previous article, the method area mainly stores the runtime data structure of the Class. The various data structure information of the Class in the method area is accessed through the Class instance.

The diagram below:

The method area, where the classes are loaded in, employs two types of workers:

  • ** Class loader: ** is responsible for managing the class information of each storage area, such as loading and unloading class information;
  • **Class instance: ** is responsible for connecting external requirements, if external people want to see the inside of the Class information, you need to use the Class instance to obtain;

In addition, in the method area, the information about the launch class loader is visible to the extension two class loaders, and the information about the first two classes is visible to the application class loader.

3. Other examples of non-parental delegation models

3.1 JDK 1.0 legacy issues

In JDK1.0 there was a ClassLoader class, but there was no parent delegate mechanism. Users needed to reload class () methods to customize class loaders. To implement a custom class loader, you simply need to re-findClass ().

If the loadClass() method is redone, it means that the parental delegation model is no longer followed.

3.2. Thread context classloader

Why do we need this? Let’s start with a case study.

Class loaders in Tomcat

We know that the Tomcat directory structure has the following directories:

  • /common/ : Class libraries in this directory can be used by Tomcat and all webApps;

  • /server/ : The class library in this directory can be used by Tomcat, but is not visible to all WebApps;

  • /shared/ : The class library in this directory can be used by all WebApps, but is not visible to Tomcat itself;

In addition, the Web application has its own class library, located in the /WebApp/WEB-INF directory: this class library is only used by the Web application, and is not visible to Tomcat or other Web applications. Tomat provides the following custom class loaders to achieve library visibility for each of these directories:

Now here’s the scenario:

We found that Tomcat has several webApps, each of which uses Spring, so we put the Spring JAR package in the shared directory.

So the question arises: Since spring jars are loaded by Shared class loaders, assuming we want to use SpringContext’s getBean method to get beans from webApp, we would have a problem using the parent delegate model. Because Java classes in WebApp are not visible to SharedClassLoader:

Thread context classloader in Spring

To solve this problem, Spring uses the thread-context classloader, which gets the current thread’s context class loader from ThreadLocal, to load all the libraries and classes.

For interpretation of Spring initialization source code, refer to my article: Spring IoC Principle Anatomy.

The bean classloader in Spring

ApplicationContext has a beanClassLoader field, which is the bean’s classloader and is initialized in the prepareBeanFactory() method:

beanFactory.setBeanClassLoader(getClassLoader());
Copy the code

GetClassLoader:

	@Override
	@Nullable
	public ClassLoader getClassLoader(a) {
		return (this.classLoader ! =null ? this.classLoader : ClassUtils.getDefaultClassLoader());
	}
Copy the code

ClassUtils. GetDefaultClassLoader () method:

	@Nullable
	public static ClassLoader getDefaultClassLoader(a) {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		}
		catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back...
		}
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			cl = ClassUtils.class.getClassLoader();
			if (cl == null) {
				// getClassLoader() returning null indicates the bootstrap ClassLoader
				try {
					cl = ClassLoader.getSystemClassLoader();
				}
				catch (Throwable ex) {
					// Cannot access system ClassLoader - oh well, maybe the caller can live with null...}}}return cl;
	}
Copy the code

As you can see, the ClassLoader in the current thread context is finally fetched.

Load the beans

Let’s look at the code for Spring to load the Class. Here we go straight to the method for instantiating Singletons and follow along to find the code to focus on:

We found that this method was called when loading the Bean Class:

AbstractBeanFactory:

ClassLoader beanClassLoader = getBeanClassLoader();
Copy the code

The beanClassLoader in ApplicationContext is used to load the Bean Class instance.

conclusion

Spring, as a third-party class library, can be loaded by any ClassLoader, so the most flexible approach is to use the context ClassLoader directly.

3.3. Module hot deployment

It’s mainly modular hot deployment technologies like OSGi. In OSGi there is no longer a tree structure like the parent delegate model, but a more complex network structure.

References

Where are static methods and static variables stored in Java?

ClassLoader in Java

Really Understand thread-context classloaders (Multi-case Study)

In-depth Understanding of the Java Virtual Machine – Advanced JVM Features and Best Practices

Chapter 5. Loading, Linking, and Initializing


This article is written by Arthinking based on relevant technical information and official documentation. It is accurate to ensure that the content is correct. If you find any mistakes or errors, please kindly correct them.

You can follow my blog at itzhai.com for more articles, and I will continue to update on back-end technologies, including THE JVM, Java infrastructure, architectural design, network programming, data structures, databases, algorithms, concurrent programming, distributed systems, and more.

If you feel that you have gained something after reading this article, you can follow my account, or like, your support is my motivation to write! Follow my official account for the latest articles.


Author: Arthinking

Blog link: www.itzhai.com/jvm/what-is…

An illustration to thoroughly understand the class loader and parent delegate mechanism

Copyright notice: copyright belongs to the author, shall not be reproduced without permission, infringement will be investigated! Please add the public number to contact the author.