On the Java class loader classloader

Analysis of this article to look at the application classloader in Java.

Foreword

Now a general application development will contain a lot of class, a Java program starts not at one time all the classes were all loaded into memory to run, but the first part of the class is loaded into the JVM, then JVM, etc. need to the other classes and then loaded into, this advantage is to save memory and improve efficiency.

In Java class loader is ClassLoader, ClassLoader specific role is to load the class files into jvm virtual machine to the program can be run properly.

Class Recognition

We usually write the Java file format is xxx.java file format, this format is not a format JVM execution, the JVM is executed .class file format, which requires the .java .class format documents into a format this is the compilation process. Command is:

javac HelloWorld.java
复制代码

To generate .class files in the current directory by javac command, this file is the file format JVM can perform.

Here Insert Picture Description

Then you can run the file through java command:

java HelloWorld
复制代码

Printing results are shown below:

Here Insert Picture Description
The above is a complete Java file to run the process, the first compiled into .class .java file format in order to be able to perform JVM. Next, we analyze in detail.

Java class loader

ClassLoader classification

Each ClassLoader objects are instances of a java.lang.ClassLoader. Each Class objects are loaded ClassLoader these objects can be extended by subclassing ClassLoader defined by the java.lang.ClassLoader, and use these custom ClassLoader class loaded.

package java.lang;
public abstract class ClassLoader {
	 public Class loadClass(String name);
	 protected Class defineClass(byte[] b);
	 public URL getResource(String name);
	 public Enumeration getResources(String name);
	 public ClassLoader getParent();
	 Class<?> findClass(String name)
     //...
}
复制代码

1,loadClass

It accepts a full class name, and returns an instance of Class type.

2,defineClass

The method of receiving a group of bytes, and then into a specific instance of Class type, it is generally loaded from a file on disk, then the bytes of the file is transmitted to the JVM, by JVM (native methods) defined for the Class, which concrete, instantiate an instance of Class type.

3,getParent

Return to their parent ClassLoader

We actually demo to test.

package demo;
public class Test {
    public static void main(String[] args) {
        ClassLoader classLoader = Test.class.getClassLoader();
        System.out.println(classLoader);
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);
    }
}
复制代码

Print results are as follows:

sun.misc.Launcher$AppClassLoader@135fbaa4
sun.misc.Launcher$ExtClassLoader@2503dbd3
null
复制代码

The following three types of load ClassLoader in Java:

  1. Bootstrp loader
  2. ExtClassLoader
  3. AppClassLoader

In fact, the above demo print out the results to verify the three ClassLoader.

(1): root class loader (null)

It is implemented by native code (c / c ++), and you do not get his quote, but he actually exists, and load some important classes, it loads (% JAVA_HOME% \ jre \ lib), as rt.jar (runtime), i18n.jar, these are the core Java classes.

(2): extension class loader (ExtClassLoader)

Although they will get, but we rarely used it in practice, it is mainly loaded jar package under the extension directory,% JAVA_HOME% \ lib \ ext

(3): application class loader (the AppClassLoader)

It is mainly load our application class, such as Test, or the use of third-party packages, such as jdbc driver package and so on.

Here parent class in the class loader to distinguish the concept of inheritance, which is not defined in the class of the parent-child relationship.

Class loader calls the order

The same, ClassLoader in Java there is a way to call the order, we have to resolve the above Test.java classes.

When Test.class to be loaded, it will start the application class loader to load the Test class, but this does not really apply class loader to load him, but will call to see if there is a parent loader, resulting in, is extension class loader, the extension class loader will not go directly to the load, it is to see whether they have a parent loader did not result it is still there, is the root class loader.

So this time went to the root class loader loads the class, may in% JAVA_HOME% \ jre \ lib, it can not find demo.Test this class, so he told his son the class loader, I can not find you to load it, the subclass extension class loader to% JAVA_HOME% \ lib \ ext go, could not find, it tells its subclasses loader AppClassLoader, I can not find this class, you go to load it, the results found AppClassLoader , and it is added to the memory and to generate Class object.

Borrow a map to represent the online process.

Here Insert Picture Description

This figure obviously shows ClassLoader of the order of execution.

Parents entrust

Parents entrust that is, "when there is a demand class loader class is loaded, it will first consult its Parent uses its search path to help load, if Parent is not found, then only by themselves in accordance with their own search path search category," goes above it shows the flow of FIG.

We still use the code above will be described:

package demo;
public class Test {
    public static void main(String[] args) {
    
        ClassLoader classLoader = Test.class.getClassLoader();
        System.out.println(classLoader);
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);
    }
}
复制代码

Print results are as follows:

sun.misc.Launcher$AppClassLoader@135fbaa4
sun.misc.Launcher$ExtClassLoader@2503dbd3
null
复制代码

Print results can be seen, Test is AppClassLoader loader loaded, AppClassLoader the Parent loader is ExtClassLoader, but ExtClassLoader of Parent is null how it is uh, friends paid attention to it, in front of Bootstrap Loader is mentioned in C ++ when writing, depending on java point of view, there is no class of entities Bootstrap Loader logically, so try to print out the contents of java program code, we will see the output is null.

Why should "trust mechanism"? Can be considered from the safety aspect, if a malicious person to write a base class (such as java.lang.String) and loaded into the JVM will cause serious consequences, but with overall responsibility, java.lang.String forever by loader to load the root, to avoid the above situation occurs.

If we wrote a java.lang.String class, whether we can replace JDK classes tune itself?

the answer is negative. We can not achieve. why? I see a lot of online explanation is that parents trust mechanism to solve this problem, in fact, not very accurate. As the parent delegation mechanism can be broken, you can write a classLoader to load write their own java.lang.String class, but you will find will not be loaded successfully, in particular because for java. * At the beginning of class, jvm implementation has pledged that must be loaded by bootstrp.

Custom ClassLoader

Since the system already exists in three ClassLoader why do we need our own ClassLoader define it? Because the default ClassLoader Java provided to load only the specified directory the following jar and class, but if we need to load the rest of the jar and class is powerless, and this time we need our own to achieve the ClassLoader. We know from above ClassLoader is an abstract class that implements custom ClassLoader need to inherit the class and inside methods. Under normal circumstances, we rewrite findClass parent class can be.

package java.lang;
public abstract class ClassLoader {
	 public Class loadClass(String name);
	 protected Class defineClass(byte[] b);
	 public URL getResource(String name);
	 public Enumeration getResources(String name);
	 public ClassLoader getParent();
	 Class<?> findClass(String name)
	 //...
}
复制代码

Why are so many methods ClassLoader only rewrite findClass method? Since JDK loadClass method has helped us to achieve in the search algorithm ClassLoader class, when not search loadClass method in class, loadClass method is called findClass way to search the class, so we need to override this method. If no special requirements, generally not recommended to rewrite the loadClass search algorithm class.

Exemplary custom ClassLoader

If we define a custom classloader we can write a test class to show. Hello below to create a new class in the current directory. Inside there is a way to specify the following sayHello then placed in a directory, such as: my current directory:

/Users/java/intellidea/JavaTest/src/demo/Hello.java

package demo;
public class Hello {
    public void sayHello() {
        System.out.println("say hello ------> classloader");
    }
}
复制代码

Then we need to inherit a custom ClassLoader ClassLoader system. We named HelloClassLoader class.

package demo;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class HelloClassLoader extends ClassLoader {
    private String mLibPath;
    public HelloClassLoader(String path) {
        mLibPath = path;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String fileName = getFileName(name);
        File file = new File(mLibPath,fileName);
        try {
            FileInputStream is = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len = 0;
            try {
                while ((len = is.read()) != -1) {
                    bos.write(len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] data = bos.toByteArray();
            is.close();
            bos.close();
            return defineClass(name,data,0,data.length);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return super.findClass(name);
    }
    //获取要加载 的class文件名
    private String getFileName(String name) {
        // TODO Auto-generated method stub
        int index = name.lastIndexOf('.');
        if(index == -1){
            return name+".class";
        }else{
            return name.substring(index)+".class";
        }
    }
}
复制代码

In class we HelloClassLoader to find the files we use Hello.class by findClass () method to generate a Class object. Then we write the test class HelloClassLoaderTest be measured:

package demo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class HelloClassLoaderTest {
    public static void main(String[] args) throws InvocationTargetException {
        // TODO Auto-generated method stub
        //创建自定义classloader对象。
        HelloClassLoader diskLoader = new HelloClassLoader("/Users/java/intellidea/JavaTest/src/demo");
        try {
            //加载class文件
            Class c = diskLoader.loadClass("demo.Hello");
            if (c != null) {
                try {
                    Object obj = c.newInstance();
                    Method method = c.getDeclaredMethod("sayHello", null);
                    //通过反射调用Hello类的sayHello方法
                    method.invoke(obj, null);
                } catch (InstantiationException | IllegalAccessException
                        | NoSuchMethodException
                        | SecurityException |
                        IllegalArgumentException |
                        InvocationTargetException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
复制代码

According to the results of the test class prediction should print:

say hello ------> classloader
复制代码

This line is we have a method in the Hello class sayHello printed inside. We run the above code, view the printed results:

Here Insert Picture Description

As you expect the same, print out the correct result. The above is a simple implementation of custom ClassLoader class.

to sum up

The above is about the content of Java ClassLoader inside, there are yet involved, the next step is research ClassLoader to use the content in Android.

About the Author

Focus on Android development for many years, likes to write blog records summarize learning experience, synchronized updates on my blog public number, welcome everyone's attention, can talk about ~

Here Insert Picture Description

Guess you like

Origin juejin.im/post/5ddde2bce51d4533066bfe9d