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 the
Program first initiative
LinkageError 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 the
loadClass
methods - In 3.
loadClass
Method that implements class bytecode loading, returning byte[] - 4. Call
super.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 changedAppClassLoader
The 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 namespaceNameSpace
Because 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. Call
findLoadedClass
Method to check if the class is loaded - 2. Call the parent loader
loadClass
Method, which calls the JVM’s built-in class loader if the parent loader is null. - 3. Call
findClass
Method finding class
In the default loadClass method, class loading issynchronous
the
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 JVM
Same 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.getSystemClassLoader
The 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
SystemClassLoaderAction
logic
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 theclassloader
, loads the classloader for this class
Thread context loader (ContextClassLoader
) implementation and analysis
CurrentClassLoader(CurrentClassLoader)
- Each class will try to use its own
ClassLoader
To 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)
- Thread.currentThread().getContextClassLoader()
- 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.