Class loaders:
Class loading refers to reading a class’s class file into memory and creating a java.lang. class object for it. That is, when any class is used in a program, the system creates a java.lang. class object for it.
By using different class loaders, you can load the binary data of a class from different sources, usually the following.
-
Load a class file from the local file system, which is how most of the previous sample programs load classes.
-
It is also common to load a class file from a JAR package. The database driver classes used for JDBC programming are in the JAR file, and the JVM can load the class file directly from the JAR file.
-
Load class files over the network.
-
Dynamically compile and load a Java source file.
The Java Virtual Machine specification allows the system to pre-load certain classes. When a Class is loaded, the system generates a corresponding Class object for it and then enters the connect phase, which merges the binary data of the Class into the JRE. Class join can be divided into the following three stages.
-
(1) Verification: The verification stage is used to check whether the loaded class has the correct internal structure and is consistent with other classes.
-
(2) Preparation: The class preparation stage is responsible for allocating memory for the static Field of the class and setting the default initial value.
-
(3) Parsing: Replace symbolic references in the binary data of the class with direct references.
When a class is loaded using the loadClass() method of the ClassLoader class, the method simply loads the class and does not perform initialization of the class.
Using the static forName() method of the Class causes the Class to be forcibly initialized. For example, the following code.
class Tester {
static {
System.out.println("Static initializer block for Tester class..."); }}public class ClassLoaderTest {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader cl = ClassLoader.getSystemClassLoader();
// The following statement simply loads the Tester class
cl.loadClass("Tester");
System.out.println("System loads Tester class");
// The following statement initializes the Tester class
Class.forName("Tester"); }`
}
Copy the code
The class loader is responsible for loading the.Class file (either on disk or on the network) into memory and generating the corresponding Java.lang.class object for it
When the JVM starts, an initial class loader hierarchy is formed consisting of three class loaders.
-
Bootstrap ClassLoader: root ClassLoader.
-
Extension ClassLoader: Extension ClassLoader.
-
System ClassLoader: System ClassLoader.
The Bootstrap ClassLoader is called the boot (also known as the original or root) ClassLoader, which is responsible for loading Java’s core classes. In Sun’s JVM, when executing the java.exe command, you can specify additional classes to load using the -xbootclasspath option or specifying the value of the sun.boot.class.path system property with the -d option.
The root ClassLoader is special in that it is not a subclass of java.lang.ClassLoader, but is implemented by the JVM itself.
Parental delegation model:
There are three main JVM class loading mechanisms:
-
Take full responsibility. Full responsibility means that when a Class loader is responsible for loading a Class, other classes that that Class depends on and references are also loaded by the Class loader, unless another Class loader is explicitly used to load the Class.
-
Superclass delegate. A parent delegate lets the parent Class loader try to load the Class, and only tries to load the Class from its own classpath if the parent Class loader is unable to load the Class.
-
Caching mechanism. The caching mechanism will ensure that all loaded classes will be cached. When a program needs to use a Class, the Class loader first searches for the Class in the cache. Only when the Class object does not exist in the cache, the system will read the binary data corresponding to the Class, convert it into a Class object, and store it in the cache. This is why after Class changes are made, the JVM must be restarted for the program’s changes to take effect.
Note:
The parent-child relationship between class loaders is not the parent-child relationship in class inheritance, but the parent-child relationship between class loaders instances.
The Class loader goes through the following eight steps to load a Class.
-
1) Check whether the Class has been loaded (that is, whether the Class is in the cache), if so go to step 8, otherwise proceed to Step 2.
-
(2) If there is no parent class loader (if there is no parent class loader, then either parent must be the root class loader or the root class loader itself), then skip to step 4. If the parent class loader exists, then step 3 is performed.
-
(3) Request the parent class loader to load the target class, if successful, skip to step 8, otherwise proceed to step 5.
-
(4) Request the root class loader to load the target class, if successful, skip to step 8, otherwise skip to step 7.
-
(5) The current ClassLoader tries to find the Class file (from the classpath associated with this ClassLoader), if it finds it, perform step 6, if not, skip to step 7.
-
(6) Load the Class from the file and skip to step 8.
-
(7) Throw ClassNotFoundException.
-
(8) Return the corresponding java.lang.Class object.
public class URLClassLoaderTest {
private static Connection conn;
// Define a method to get a database connection
public static Connection getConn(String url, String user, String pass) throws Exception {
if (conn == null) {
// Create an array of urls
URL[] urls = {new URL("File: mysql connector - Java - 3.1.10 - bin. Jar")};
// Use the default ClassLoader as the parent ClassLoader
URLClassLoaderURLClassLoader myClassLoader=new URLClassLoader(urls);
// Load the MySQL JDBC driver and create a default instance
Driver driver=(Driver)myClassLoader.loadClass("com.mysql.jdbc.Driver").newInstance();
// Create a Properties object that sets the JDBC connection Properties
Properties props = new Properties();
// You need to pass in at least two attributes, user and password, for this object
props.setProperty("user", user);
props.setProperty("password", pass);
// Call the connect method of the Driver object to get the database connection
conn = driver.connect(url, props);
}
return conn;
}
public static volid main(String[] args) throws Exception {
System.out.println(getConn("jdbc:mysql://localhost:3306/mysql"."root"."32147")); }}Copy the code
Again, the parental delegation model:
Parents delegate mechanism, its working principle is that if a class loader received class loading request, it will not go to loading, but delegates the request to the parent class loader to execution, if the parent class loader is its parent class loader, further upward, recursive in order, the request will eventually reach the top of start the class loader, If the parent class loader finish class loading can be successfully returns, if the parent class loader cannot complete the task load, child loader will try to load, it is the parents delegate pattern, namely every son is lazy, every time you lost to his father to do, I was good until his dad said it, his son just think of some way to go to complete, is the mechanism on dad.
Advantages of parent delegation: The advantage of using parent delegation is that Java classes have a hierarchy of priorities along with their classloaders. This hierarchy avoids reloading classes. There is no need for the child ClassLoader to load the class once the parent has already loaded the class. Second, for security reasons, defined types in the Java core API will not be arbitrarily replaced. Suppose that a class named java.lang.Integer is passed over the network through the parent delegate mode to the initiator class loader, and the initiator class loader finds the class with this name in the core Java API and finds that the class has been loaded. Instead of reloading java.lang.Integer passed by the network, integer.class is returned, which prevents the core API library from being tampered with.
System implementation of parental delegation model:
In the java.lang.classloader loadClass() method, first check whether it has been loaded. If not, the parent loadClass() method is called. If the parent is empty, the startup ClassLoader is used as the parent by default. If the parent load fails, throw a ClassNotFoundException and then call your own findClass() method to load
protected synchronizedClass<? > loadClass(String name,boolean resolve)throws ClassNotFoundException{
//check the class has been loaded or not
Class c = findLoadedClass(name);
if(c == null) {try{
if(parent ! =null){
c = parent.loadClass(name,false);
}else{ c = findBootstrapClassOrNull(name); }}catch(ClassNotFoundException e){
//if throws the exception ,the father can not complete the load
}
if(c == null){ c = findClass(name); }}if(resolve){
resolveClass(c);
}
return c;
}
Copy the code
That’s what class loading is all about today, but there are a lot of details I haven’t covered until I get a chance to talk more about it.