1. After jdk1.2, class loading is completed through delegation. This means that if the classloader cannot find the class, it will request the parent classloader to execute this task, the root of all classloaders is the system classloader, which loads the class by default-that is, from the local file system. Today we will discuss how these mechanisms run in JVM. Let's assume there is a class bytecode file (such as the hello. Class file). How is it loaded in the application and formed into a class object? The purpose of this article is to explain this question.
There is a classloader class in the Java. lang package. The basic goal of classloader is to provide services for class requests. When the JVM needs to use a class, it requests this class from classloader according to the name, and then classloader tries to return a class object that represents this class. You can create a custom classloader by overwriting methods corresponding to different stages of the process. There is a loadclass (string name, Boolean resolve) method, which is the entry point of classloader. After jdk1.2, The loadclass method will call the findclass method by default. For details, refer to the API documentation, the classloader we wrote mainly aims to overwrite the above two methods. Back to our question, how can we read the bytecode file and make it a class object? There is a method in classloader, class defineclass (string name, byte [] B, int off, int Len), the answer is here, based on the class bytecode file (such as hello. class) read into a byte array, byte [] B, and convert it into a class object, and the data can come from files, networks, etc., amazing :)
Defineclass manages many of the complex, mysterious, and implementation-dependent aspects of JVM-It analyzes bytecode into runtime data structures, verifies validity, and so on. Don't worry, you don't need to write it yourself. In fact, even if you want to do so, you cannot overwrite it because it has been marked as final.
Other methods:
Findsystemclass method: load files from the local file system. It looks for a class file in the local file system. If it exists, it will use defineclass to convert the original byte to a class object to convert the file to a class.
Findclass method: the new method is called by the default Implementation of loadclass after jdk1.2. The purpose of findclass includes all the special code of your classloader without the need to copy other Code (for example, when a special method fails, the system classloader is called ).
Getsystemclassloader: If it overwrites findclass or loadclass, getsystemclassloader enables you to access the system classloader with the actual classloader object (instead of calling it from findsystemclass ).
Getparent: to delegate a class request to the parent classloader, this new method allows the classloader to obtain its parent classloader. This method can be used when a custom classloader cannot find a category.
Resolveclass: you can load classes not completely (without resolution), or completely (with resolution. When writing our own loadclass, you can call resolveclass, depending on the resolve parameter value of loadclass.
Findloadedclass: acts as a cache. When loadclass is requested to load the class, it calls this method to check whether the class has been loaded. This avoids the trouble of re-loading existing classes. Call this method first.
Ii. workflow:
1) Call findloadedclass (string) to check whether a mounted class exists. If not, use the special magic method to obtain the original bytes.
2) Call the loadclass method through the parent class classloader. If the parent class classloader is null, the class is loaded by default, that is, the system classloader.
3) Call findclass (string) to find the class and obtain the class;
4) if the resolve parameter value of loadclass is true, call resolveclass to parse the class object.
5) If no class exists, return classnotfoundexception.
6) Otherwise, return the class to the caller.
3. An example of classloader implementation:
/** * Compilingclassloader. Java * Copyright 2005-2-12 */ Import java. Io .*;Public class compilingclassloader extends classloader { // Read the content of a file Private byte [] getbytes (string filename) throws ioexception { File file = new file (filename ); Long Len = file. Length (); Byte [] Raw = new byte [(INT) Len]; Fileinputstream fin = new fileinputstream (File ); Int r = fin. Read (raw ); If (R! = Len) throw new ioexception ("can't read all," + R + "! = "+ Len ); Fin. Close (); Return raw; } Private Boolean compile (string javafile) throws ioexception { System. Out. println ("CCL: Compiling" + javafile + "..."); // Call the javac command of the system Process p=runtime.getruntime(cmd.exe C ("javac" + javafile ); Try { // Other threads are waiting for this thread to complete P. waitfor (); } Catch (interruptedexception IE ){ System. Out. println (IE ); } Int ret = P. exitvalue (); Return ret = 0; } Public class loadclass (string name, Boolean resovle) throws classnotfoundexception { Class CLAS = NULL; Clas = findloadedclass (name ); // The package representation is described here. String filestub = Name. Replace ('.','/'); String javafilename = filestub + ". Java "; String classfilename = filestub + ". Class "; File javafile = new file (javafilename ); File classfile = new file (classfilename ); // If a class file exists, it is not compiled. If (javafile. exists ()&&(! Classfile. exists () | javafile. lastmodified ()> classfile. lastmodified ())){ Try { If (! Compile (javafilename) |! Classfile. exists ()){ Throw new classnotfoundexception ("classnotfoundexcetpion:" + javafilename ); } } Catch (ioexception IE ){ Throw new classnotfoundexception (ie. tostring ()); } } Try { Byte [] Raw = getbytes (classfilename ); // Construct a class structure by reading data, which is the core Clas = defineclass (name, raw, 0, raw. Length ); } Catch (ioexception IE ){ // } If (CLAS = NULL ){ Clas = findsystemclass (name ); } System. Out. println ("findsystemclass:" + CLAS ); If (resovle & CLAS! = NULL ){ Resolveclass (CLAS ); } If (CLAS = NULL ){ Throw new classnotfoundexception (name ); } Return CLAS; } } Test the loader: /** * Testrun. Java * Copyright 2005-2-11 */ Import java. Lang. Reflect .*; Public class testrun { Public static void main (string [] ARGs) throws exception { String progclass = ARGs [0]; String progargs [] = new string [args. Length-1]; System. arraycopy (ARGs, 1, progargs, 0, progargs. Length ); Compilingclassloader CCL = new compilingclassloader (); Class CLAS = CCL. loadclass (progclass ); // Return the type of a class Class [] mainargtype = {(New String [0]). getclass ()}; Method main = Clas. getmethod ("Main", mainargtype ); Object argsarray [] = {progargs }; Main. Invoke (null, argsarray ); } } |
The above core content has been compiled. After compilation, we get two files:
Compilingclassloader. Class, testrun. Class
4. Compile an example and run our classloader
/** * Hello. Java */ Public class Hello { Public static void main (string [] ARGs ){ If (ARGs. length! = 1 ){ System. Err. println ("error, exit! "); System. Exit (1 ); } String name = ARGs [0]; System. Out. println ("hello," + name ); } } |
Okay, run Java testrun Hello afei.