What did we know about the JVM in the previous article? In this article (all of which is based on HotSpot JVM as an example) let’s take a look at the ClassLoader, which is responsible for loading Class bytecode files from the file system or network and loading Class information (DNA metadata templates, The JVM instantiates n identical instances from this template) in the “methods area” (more on that in a future article). The ClassLoader is only responsible for loading files, and it is up to the Exection Engine (more on that in the next article) to decide whether a file can be run.

Below is the class loading subsystem construction diagram:

Class loading process

Loading

Loading process

  1. Gets the binary byte stream that defines a class by its fully qualified name;
  2. Convert the static storage structure represented by this byte stream to the runtime data structure of the method area;
  3. Generates an in-memory representation of this classjava.lang.ClassObject that acts as an access point to the various data of the class called the method area.

loading.classFile mode

  • Load directly from the local system;
  • Obtain the IP address from the network. Typical scenarios:Web Applet;
  • Read from the zip package and become the futurejar,warThe basis of the format;
  • Runtime computational generation, most commonly used are: dynamic proxy techniques;
  • The file is generated by other files. Typical scenarios:jspApplication;
  • Extracted from a proprietary database.classDocuments, relatively rare;
  • Read from an encrypted file, typically againstClassProtection against files being decompiled.

Linking

(1) Verify

  • The purpose is to ensureClassThe byte stream in the file meets the requirements of the current VM, ensuring the correctness of the loaded classes and not compromising vm security.
  • There are four authentication methods: file format authentication, metadata authentication, bytecode authentication and symbol reference authentication.

File format verification: Verifies that the byte stream complies with the Class file format specification and can be loaded by the current VIRTUAL machine. For example, check whether the major and minor versions are in the range processed by the current VM. Are there any unsupported constant types in the constant pool? An index value in a pointer to a constant that does not exist or does not conform to a type.

Metadata verification: Semantic analysis of the information described by bytecode to analyze whether it conforms to the specification of Java language syntax.

Bytecode validation: The most important validation step, analyzing the data flow and control to determine that the semantics are legitimate and logical. The main purpose is to verify the method body after metadata verification. Ensure that class methods do not have hazards at runtime.

Symbol reference verification: mainly for the conversion of symbol reference to direct reference, it will extend to the third parsing stage, mainly to determine the access type and other situations involving references, mainly to ensure that the reference will be accessed, there will be no class inaccessible problems.

Java VIRTUAL machine bytecode file start encoding CAFEBABE (using Binary Viewer software)

They are preparing for the exam.

  • Allocates memory for class variables (static variables) and sets the default initial value of the class variable, which is zero.
Public class HelloWord{private static int a=1; private static int a=1; public static void main(){ System.out.println(a); }}Copy the code
  • It doesn’t containfinalModification of thestaticBecause thefinalIt is allocated at compile time, and initialization is displayed during preparation;
  • There is no allocation initialization for instance variables (objects of new). Class variables are allocated in the method area and instance variables are allocated along with the objectjavaThe heap.

(3) Resolve

The process of converting a symbolic reference in a constant pool (a symbolic reference is a set of symbols that describe the referenced target) to a direct reference (a direct reference is a pointer to the target, a relative offset, or a handle that is succinctly positioned to the target). In fact, parsing operations are often performed with the JVM after initialization. Parsing actions are for classes or interfaces, fields, class methods, method types, and so on. Corresponding to CONSTANT_Class_info, CONSTANT_Fieldref_info, and CONSTANT_Methodref_info in the constant pool.

The execution of parsing will be explained later when we talk about bytecode files.

Initialization

  • The initialization phase is to execute the class constructor method<clinit>()In the process. This method does not need to be defined, yesjavacThe compiler automatically collects everything in a classClass variablesThe assignment action andStatic code blockStatement from the. The instructions in the constructor methods are executed in the order in which the statements appear in the source file.<clinit>()Unlike class constructors, constructors are from the virtual machine perspective<init>().
  • If the class has a parent class, the JVM guarantees subclasses<clinit>()Before execution, the parent class<clinit>()The execution is complete.
  • The virtual machine must be guaranteed a class of<clinit>()Methods are locked synchronously in multiple threads.

Sample:

Calling before definition results in an “illegal forward reference” error

Class initialization timing

Java programs can use classes in two ways:

1. Use it actively

  • Create an instance of the class
  • Accesses or assigns a value to a static variable of a class or interface
  • Call a static method of a class
  • reflection
  • Initialize a subclass of a class
  • Java virtual machine startup classes that are identified as startup classes
  • Dynamic language support starting with JDK 7:java.lang.invoke.MethodHandleThe parsing result of the instance,REF_getStatic,REF_putStatic,REF_invokeStaticIf the class corresponding to the handle is not initialized, it is initialized.

2. Passive use: All but the seven cases above are considered passive use of the class and do not result in class initialization.

Class loader

Loader classification

The JVM supports two types of classloaders: the boot classloader (Bootstrap ClassLoader) and custom loaders (User-Defined ClassLoader), the relationship between them is not inheritance, but inclusion.

Bootstrap the classloader

The boot class loader, also known as the boot class loader, is implemented in C/C++ and is nested within the JVM. It is used to load Java’s core libraries (JAVA_HOME/jre/lib/rt.jar, resources.jar, or sun.boot.class.path) to provide classes that the JVM itself needs. The Bootstrap startup class loads only classes whose package names start with Java, Javax, and Sun. It does not inherit from java.lang.ClassLoader and has no parent loader.

//String belongs to Java's core class library --> loaded with the boot class loader
ClassLoader classLoader1 = String.class.getClassLoader();
System.out.println(classLoader1);//null
Copy the code

Custom loader

Custom loaders refer to all class loaders derived from the abstract CLassLoader, which is divided into extension class loaders, application (system) loaders and user – defined loaders.

(1) Extend the class loader

Java language by sun. Misc. The Launcher. ExtClassLoader implementation. The parent class loader loads the class libraries from the directory specified by the java.ext.dirs system property, or from the JRE /lib/ext subdirectory (extension directory) of the JDK installation directory. If user-created jars are placed in this directory, they will also be automatically loaded by the extended class loader.

(2) System loader

Java language by sun. Misc. The Launcher. AppClassLoader implementation. The parent class loader is the extension class loader that loads the class libraries in the path specified by the environment variable classpath or system properties, java.class.path. Class loaders are the default class loaders in your program.

// Get the system class loader
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

// Get its upper layer: extension class loader
ClassLoader extClassLoader = systemClassLoader.getParent();
System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@4554617c

// Get the boot class loader
ClassLoader bootstrapClassLoader = extClassLoader.getParent();
System.out.println(bootstrapClassLoader);//null
Copy the code

(3) User-defined loader

Developers can implement custom classloaders by inheriting the abstract java.lang.classloader class and implementing the findClass() method. When writing a custom class loader, if you don’t have too complicated requirements, you can inherit the URLClassLoader class directly. This way, you can avoid writing the findClass() method and the way to get the bytecode stream, making the custom class loader writing simpler.


// User-defined classes are loaded using the system class loader by default
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

Copy the code

Why custom loaders?

  • Isolate load classes;
  • Modify the class loading method;
  • Extended load source;
  • Prevent source code leakage;

ClassLoader and API

To obtain

  1. Gets the value of the current classClassLoader:clazz.getClassLoader();
  2. Gets the current thread contextClassLoader:Thread.currentThread().getContextClassLoader();
  3. Access systemClassLoader:ClassLoader.getSystemClassLoader();
  4. Gets the caller’sClassLoader:DriverManager.getCallerClassLoader();

API

  • Class loadClass(String name) : name specifies the name of the Class to be loaded by the Class loader. The fully qualified Class name must be used, for example:com.smart.bean.Car. This method has an overloaded methodLoadClass (String name, Boolean resolve) ` `,The resolve ‘parameter tells the class that it needs to be resolved when it is loaded. Class resolution is considered before initialization, but not all classes need to be resolved. If the JVM only needs to know if the class exists or find out its superclasses, no parsing is required.
  • Class defineClass(String name,byte[] b,int len) : Converts a Class file’s byte array into an internal JVMjava.lang.ClassObject. Byte arrays can be retrieved from local file systems, remote networks. The parameter name is the fully qualified class name for the byte array.
  • Class findSystemClass(String name) : Load from the local file systemClassFile. If this parameter does not exist in the local systemClassFile. The thrownClassNotFoundExceptionThe exception. This method is the default loading mechanism used by the JVM
  • Class findLoadedClass(String name) : Call this method to seeClassLoaderWhether a class has been loaded. Returns if it is loadedjava.lang.ClassObject; Otherwise returnsnull. If an existing class is forcibly loaded, a link error is thrown.
  • ClassLoader getParent() : gets the parent loader of the ClassLoader. All class loaders except the root loader have one and only one parent loader.ExtClassLoaderThe parent loader is the root loader because the root loader is notjavaLanguage written, so cannot get, will returnnull.

Parent delegation mechanism

The Java virtual machine loads class files on demand, which means that it loads its class files into memory to generate class objects when the class is needed. In addition, when loading a class file, the Java VIRTUAL machine adopts the parental delegation mode, that is, the request to the parent class processing, which is a kind of task delegation mode.

The working principle of

If a classloader receives a classload request, it does not load the request itself. Instead, it delegates the request to the parent class’s loader. If the parent class loader also has a parent class loader, delegate further up, recursively, and the request will eventually reach the top level of the start class loader. If the parent class loader can complete the task, it returns successfully. If the parent class loader cannot complete the task, the child loader will try to load itself. This is the parent delegate mode.

advantage

  • Avoid reloading classes; there is no need for children when the parent has already loaded the classClassLoaderLoad it again.
  • Protect program security and prevent the core API from being tampered with. The following is an example code screenshot

As shown in the figure, we create the java.lang.String class. When loading the custom class, we use the boot class loader to load the custom class. The boot class loader loads the JDK files (Java /lang/String.class in rt.jar). The error message says there is no main method because the String class from rt.jar is loaded. This ensures that the core Java source code is protected, which is called sandbox security. There are two necessary conditions for determining whether two Class objects are the same Class. First, the entire Class name must be the same, including the package name. Second, the class loader that loads the class must be the same.

A reference to the class loader

JVM must know start a class is a class loader or user class loader loads, if a class is a class loader loaded by the user, then the JVM will this class loader a reference method as part of the class information saved in the area, when parsing a class to another class of references, the JVM need to ensure that the two class class loader is the same.

That’s all for the loader part. If you are interested, you can follow the wechat public account “AH Q says the code”! You can also add a friend qingqing-4132, looking forward to your arrival!