Class loading

Loading a class means reading binary data from the class’s.class file into memory, placing it in the methods section of the runtime data area, and creating a java.lang.Class object in memory

The specification does not say where the Class object should be stored, but the HotSpot VIRTUAL machine places it in the method area to encapsulate the data structure of the Class in the method area

How to load a. Class file

  • Load directly from the local system
  • Download the. Calss file from the network
  • Load from zip, JAR, etc archives
  • Extracted from a proprietary database
  • Dynamically compile Java source files into.class files

The servlet technology

Class loader

Class loaders are used to load classes into Java virtual machines. Since JDK1.2, the loading process uses the parent delegate mechanism, which ensures the security of the Java platform.

Translation from the source documentation should be called the superclass delegate pattern

Class loaders do not need to wait until a class is first actively used to load it

  • The JVM specification allows classloaders to preload a class when they expect it to be used. If a.class file is missing or an error is encountered during preloading, the classloader must be loaded in theProgram first initiativeLinkageError is reported only when the class is used
  • If a class has not been actively used by the program, the tired loader will not report an error

Class loaders in the JVM

Root loader (Bootstrap),

Java. Lang.Object is loaded by the root class loader. The implementation of the root class loader depends on the underlying operating system, and it is the first part of the VIRTUAL machine implementation Er class. The startup class loader is a platform-specific machine instruction that is responsible for starting the entire loading process. The startup class loader is also responsible for loading the basic components needed for the JRE to function properly. These include java.util, the classes in the java.lang package

Extension class loader

The parent of the extension class loader is the root loader, which loads the class libraries from the directory specified by the java.ext.dirs system property, or from the jre\lib\ext subdirectory. If the JAR files created by the user are placed in this directory, the extension class loader is automatically loaded by the extension class loader, which is pure Java classes and is Cl A subclass of assLoader

Note that the extension class loader loads the class file inside the JAR package

Class loader (System/Application)

The parent of the system class loader is the extension class loader, which loads classes from the directory specified by the environment variable CLASspath or the system property java.class.path. It is the default parent of the user-defined class loader

User-defined class loader

In addition to the virtual machine’s own loader, users can customize their own class loaders. Java provides the abstract ClassLoader class. All user-defined loaders should inherit ClassLoader

Both AppClassLoader and ExtClassLoader are Java classes, so classloaders are required for loading, and the classloader for these two classes is bootstrapClassLoader

You can modify the default SystemClassLoader by modifying System.getProperty(java.system.class.loader)

Paternal delegation mechanism

In the parent delegate mechanism, each loader forms a tree structure according to the parent-child relationship. Except for the root loader, other class loaders have only one parent loader.

Simple description, that is, a class loader to load a class that is not loaded directly by itself, but by looking up for parent, until there is no parent class loader, and then try to load from top to bottom, until you find a can correct loading class loader, in general, the system class loader will load the ordinary class.

Not all class loaders must adhere to the mechanism of parental delegation, and the implementation can be modified as needed

Code example to view the loader for the class

public class Test08 { public static void main(String[] args) { try { Class<? > clzz = Class.forName("java.lang.String"); // If null is returned, prove BootStrapPrintln (clzz.getClassLoader()); Class<? > customClass = Class.forName("com.r09er.jvm.classloader.Custom");
            System.out.println(customClass.getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class Custom{

}
Copy the code

The output

null
sun.misc.Launcher$AppClassLoader@18b4aac2
Copy the code

The String class loader is null, indicating that the String was loaded by the Bootstrap class loader, since the root loader is implemented by C++. So null is returned.

The Custom class loader is Launcher$AppClassLoader, which is not open source. But is the default system (application) classloader.

ClassLoader and initialization timing

Load the class manually through the ClassLoader and observe whether initialization of the class is triggered

public class Test12 { public static void main(String[] args) throws Exception { ClassLoader loader = ClassLoader.getSystemClassLoader(); Class<? > aClass = loader.loadClass("com.r09er.jvm.classloader.TestClassLoader");

        System.out.println(aClass);

        System.out.println("-- -- -- -- -- -- --");

        aClass = Class.forName("com.r09er.jvm.classloader.TestClassLoader");

        System.out.println(aClass);

    }
}
class TestClassLoader{
    static {
        System.out.println("Test classloader"); }}Copy the code

The output

class com.r09er.jvm.classloader.TestClassLoader
-------
Test classloader
class com.r09er.jvm.classloader.TestClassLoader
Copy the code

conclusion

The classloader. load method is used to load a Class and does not initialize it

Different class loaders and load action analysis

Prints the class loader, which, since the root loader is written in C++, returns null

public static void main(String[] args) { ClassLoader loader = ClassLoader.getSystemClassLoader(); System.out.println(loader); // Traverses up the parent classLoaderwhile (null != loader) {
            loader = loader.getParent();
            System.out.println(loader);
        }
    }
Copy the code

The output

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@610455d6
null

Copy the code

How to obtain a ClassLoader

  • Get the ClassLoader from the class object,clazz.getClassLoader()
  • Get the upper text ClassLoader from the thread,Thread.currentThread().getContextLoader()
  • Get system (application)ClassLoader,ClassLoader.getSystemClassLoader()
  • Get the ClassLoader for the caller,DriverManager.getClassLoader()

ClassLoader source code analysis

The JavaDoc description

Classloaders are objects that load classes, and classloaders are abstract classes. Given a binary name for a class, a classloader should attempt to locate or generate the data that makes up the definition of the class. A typical strategy is to convert a binary name to a file name and then read a bytecode file for that name from the file system.

Each class object contains a classLoader reference that defines the class.

The class object corresponding to the array is not created by the class loader, but is created automatically by the Java virtual machine when needed. The class loader for an array is the same as the class loader for the array element. If the array is a native type, it will have no classLoader

String[], then the class loader for this array is the class loader for String, using the Bootstrap class loader for int[]. This basic type of array has no class loader.

Applications implement classLoader to extend the JVM’s ability to dynamically load classes

ClassLoader uses the delegate model to find the class’s resources. Each instance of a ClassLoader has an associated parent ClassLoader. When a class resource needs to be found, the ClassLoader instance is delegated to the parent ClassLoader. The built-in this virtual machine is called BootstrapClassLoader, BootstrapClassLoader itself is not the father of this, but can be used as the other father of this loader

Support concurrent load class loader is called parallel class loader, this class loader required during the class is initialized. Through this registerAsParallelCapable will register themselves. By default, it’s parallel, and subclasses need to be parallel, so you call this method

In environments where the delegate mechanism is not strictly hierarchical, the classLoader needs to be processed in parallel, otherwise the class will cause deadlocks during loading because it holds locks during loading

Typically, the JVM loads classes from the local file system, which is platform-dependent. On UNIX systems, for example, the JVM loads classes from the directory defined by the CLASSPATH in the environment variable.

However, some classes are not files, such as networks, or are built by applications (dynamic proxies). In this case, the defineClass method converts byte arrays into Class instances, which can be used to create real objects of the Class through class.newinstance Constructors and methods of objects created by class loaders may refer to other classes, so the JVM calls the loadClass method to load other referenced classes

BinaryNames, any class names provided as String arguments to methods in the ClassLoader, must be BinaryNames as defined by the Java language specification. For example,

  • “Java.lang. String”, fully qualified class name
  • “Javax.mail. Swing. A JSpinner $DefaultEditor”, inner classes
  • “java.security.KeyStoreFileBuilder$1″, anonymous inner class
  • “java.net.URLClassLoader$3$1”

Custom class loaders

steps

  • 1. This inheritance
  • 2. Rewrite theloadClassmethods
  • In 3.loadClassMethod that implements class bytecode loading, returning byte[]
  • 4. Callsuper.defineClass(byte[])Method returns a Class object to the loadClass method

The source code example

public class Test16 extends ClassLoader {

    private String classLoaderName;

    private String path;

    private final String fileExtension = ".class"; Public Test16(String classLoaderName) {// Use systemClassLoader as the parent of the current loader super(); this.classLoaderName = classLoaderName; } public Test16(ClassLoader parent, String classLoaderName) {// Use custom ClassLoader as the parent of the current loader super(parent); this.classLoaderName = classLoaderName; } public voidsetPath(String path) {
        this.path = path;
    }

    public static void main(String[] args) throws Exception {
        Test16 loader1 = new Test16("loader1"); / / set the absolute path, loading project under the root directory of the com. R09er. The JVM. This. Test01. Class loader1. SetPath ("/Users/cicinnus/Documents/sources/jvm-learning/"); Class<? > aClass = loader1.loadClass("com.r09er.jvm.classloader.Test01"); // Print the loaded class system.out.println ("loader1 load class" + aClass.hashCode());
        Object instance = aClass.newInstance();
        System.out.println("instance1: " + instance);


        Test16 loader2 = new Test16("loader2"); // Set the absolute path to load the project root directory test01.class loader2.setPath("/Users/cicinnus/Documents/sources/jvm-learning/"); Class<? > aClass2 = loader2.loadClass("com.r09er.jvm.classloader.Test01");
        System.out.println("loader2 load class" + aClass2.hashCode());
        Object instance2 = aClass2.newInstance();
        System.out.println("instance2 : "+ instance2); //todo **** //1. Recompile the project and ensure that the default classPath directory contains the test01.class bytecode file. Then run the main method and check whether //2 is displayed. Delete test01.class from the default classpath directory, run the main method, and observe the output} @override protected class <? > findClass(String name) throws ClassNotFoundException { System.out.println("invoke findClass");
        System.out.println("class loader name : " + this.classLoaderName);
        byte[] bytes = this.loadClassData(name);
        return super.defineClass(name, bytes, 0, bytes.length);
    }

    private byte[] loadClassData(String binaryName) {
        byte[] data = null;

        binaryName = binaryName.replace("."."/");

        try (
                InputStream ins = new FileInputStream(new File(this.path + binaryName + this.fileExtension));
                ByteArrayOutputStream baos = new ByteArrayOutputStream();

        ) {
            int ch;
            while(1! = (ch = ins.read())) { baos.write(ch); } data = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); }returndata; }}Copy the code

After executing the main method twice, you’ll see that the class loader actually works because the default parent loader is actually the system loader (AppClassLoader), so if the default classPath has a bytecode file, the default classPath will be changedAppClassLoaderThe class is loaded correctly, and if not in the classPath, the class is loaded down using a custom classloader

If the constructor passes in two different classLoaderNames, it will find that the two class objects are inconsistent due to the namespaceNameSpaceBecause the names of two class loaders are not the same, if they are changed to the same name, the two class objects are the same

The findClass method is overridden and is called using the loadClass method of the classLoader, which calls findClass internally

Another important point is that if you put the class bytecode file in the root directory, a NoClassDefFoundError exception will be raised because the binaryName does not conform to the specification.

Class loaders need method details

findClass

Implement your own Class loader, most importantly findClass, which loads the binaryName into a Class object by passing ina binaryName

defineClass

After you implement findClass, you need to pass the binary data to the defineClass method to convert it into a Class instance, with some protection and validation done inside defineClass.

Parent delegate mechanism parsing

When classes are loaded using the loadClass method, the default loading order is as follows

  • 1. CallfindLoadedClassMethod to check if the class is loaded
  • 2. Call the parent loaderloadClassMethod, which calls the JVM’s built-in class loader if the parent loader is null.
  • 3. CallfindClassMethod finding class

In the default loadClass method, class loading issynchronousthe

Advantages of parent delegation

  • 1. Ensure the type safety of the Java core class library. If the loading process is done by the Java application’s own class loader, it is likely that there will be multiple versions in the JVMSame class (package name, same class name).

The role of namespaces

  • 2. You can ensure that classes provided by the Java core class library are not replaced by custom classes

Because the class in the library is loaded first, custom classes are ignored

  • 3. Different classloaders can create additional namespaces for classes with the same binaryName, and classes with the same name can coexist in the JVM.

Class of unloading

Once a class is loaded, connected, and initialized, its life cycle begins. When the Class object representing the Class is no longer referenced, that is, untouchable, the Class object ends its life cycle, and the data of the Class in the meta-space is unloaded, ending the Class’s life cycle.

When a Class ends its life cycle depends on when the Class object representing it ends its life cycle

Classes loaded by the Java VIRTUAL machine’s built-in class loader are never unloaded during the lifetime of the virtual machine.

User-defined class loaders load classes that can be unloaded

The classpath loaded by the class loader

BootstrapClassLoader Loading path

  • System.getProperty(“sun.boot.class.path”)

ExtClassLoader

  • System.getProperty(“java.ext.dirs”)

AppClassLoader

  • System.getProperty(“java.class.path”)

The three paths depend on the JDK version and operating system

The compiled class bytecode file can be successfully loaded by the BootstrapClassLoader if it is placed in the load path of the root loader

Class loader namespace

  • Each class loader has its own namespace, which is made up of the classes loaded by that loader and all the parent loaders

That is, the child loader can access the classes loaded by the parent, but the parent loader cannot access the classes loaded by the child.

  • No two classes with the same full name will appear in the same namespace

A Java class is defined by its fully qualified name plus the defining classloader used to load the class.

ClassLoader.getSystemClassLoaderThe source code

Returns the system class loader used for the delegate. Is the parent of the custom class loader, which is normally loaded by the system class loader. This method is created very early in the program and sets the system class loader to be the context class loader for the calling thread.

The main logic of the Launcher construction

Initialize the ExtClassLoader. 2. Initialize the AppClassLoader and set the ExtClassLoader as the parent loader of AppClassLoader 3. Set the AppClassLoader as the context classloader for the current thread

SystemClassLoaderActionlogic

1. Check whether system.getProperty (“java.system.class.loader”) has System classloader 2. If it is empty, return AppClassLoader directly 3. If it is not empty, create a classLoader by reflection, which must provide a function signed as classLoader constructor 4. Set the custom class loader created by reflection to upper bound as loader. 5. Return the created class loader

Class.ForName(name,initialize,classloader)parsing

  • name, the fully qualified name of the class to be constructed (binaryName)

Cannot be used with primitives or void types. If an array is represented, the element class object in the array is loaded but not initialized

  • initialize, whether the class is requiredInitialize the
  • classloader, loads the classloader for this class

Thread context loader (ContextClassLoader) implementation and analysis

CurrentClassLoader(CurrentClassLoader)

  • Each class will try to use its ownClassLoaderTo load other classes referenced by the current class

If ClassA references ClassY, ClassA’s classloader will load ClassY if ClassY has not been loaded

Thread classloaders have been introduced since JDK1.2. The Thread class getContextClassLoader and setContextClassLoader are used to get and set context loaders, respectively. If not set manually, the thread inherits its parent thread’s context loader. The context classloader of the initial thread of Java application runtime is the AppClassLoader, through which classes running in the thread can load classes and resources

Problems arising from JDBC

Review JDBC operations

Class.forName("com.mysql.driver.Driver");
Connection conn = Driver.connect();
Statement stae = conn.getStatement();
Copy the code

Driver, Connection, Statement is provided by the JDK standard, and the implementation is provided by the specific DB manufacturers. According to the class loading mechanism,JDK RT packages will be loaded by BootstrapClassLoader, while custom classes will be loaded by AppClassLoader, and the parent loader cannot access the classes loaded by the child loader due to namespace reasons. So the parent loader can cause this problem.

Context loaders exist to solve this problem

The parent ClassLaoder can use classes loaded by the currentThread thread.currentthread ().getcontextclassloader (), This resolves the problem that the parent ClassLoader cannot use the child ClassLoader or that other classloaders without a direct parent relationship cannot access each other’s loaded classes.

That’s changing the paternal delegation model

Thread context loaders are generally used

Usage steps (get – Use – Restore)

  1. Thread.currentThread().getContextClassLoader()
  2. Thread.currentThread().setContextClassLoader(targetClassLoader) doSomentthing(); 3.Thread.currentThread().setContextClassLoader(originClassLoader);

The ContextClassLoader breaks Java’s classloading delegate mechanism

ServiceLoader

ServiceLoader is a simple service provider loading facility

The implementation class needs to provide a no-argument construct for reflection to construct the sample object

The service provider places the configuration file in the meta-INF /services directory of the resource directory and tells the JDK that the classes to be loaded are configured in the files in that directory, where the file name is the fully qualified name of the interface to be loaded and the file contents are the fully qualified names of one or more implementations of the classes.

conclusion

Under the parent delegate model, classes are loaded bottom-up. For SPI mechanisms, however, some interfaces are provided by Java core libraries. Depending on the class loading mechanism,JDK RT packages are loaded by BootstrapClassLoader, while custom classes are loaded by AppClassLoader. In this case, the traditional parent delegate model is not sufficient for SPI, and the interface implementation class can be loaded through the thread context loader.