Although we have read about the books of the JVM, they are all understood at the conceptual level. Today specially spent a day to study the next class loader, feel is not so unfamiliar, but also just the tip of the iceberg, simply do not completely analyze it. The content is a bit long and can be accessed quickly using the catalog.
Class Loader
The three types of class loaders that are predefined by the JVM are simply a cliché. When the JVM launches a project, it uses the following three types of ClassLoader by default:
1. Boot (Bootstrap) class loader : Responsible for loading the <Java_Home>/lib
following core class library or -Xbootclasspath
option for the specified jar package. The loading process is implemented by the native method, and the program cannot get directly to the ClassLoader and cannot perform any operations on it.
2. extension (Extension) class loader : Implemented by the extension ClassLoader sun.misc.Launcher.ExtClassLoader
. The class library that is responsible for loading <Java_Home>/lib/ext
or specifying the location by system variables -Djava.ext.dir
. The program can access and use the Extension class loader.
3. System class Loader : The system ClassLoader is sun.misc.Launcher.AppClassLoader
implemented, and in some places it is called SystemClassLoader
. is responsible for loading the -classpath
-Djava.class.path
class library under the directory referred to by the system classpath or variable. The program can access and use the System class loader.
Parent-Child delegation class-loading mechanism ClassLoader
Parent-child relationship of three kinds of loaders
Note that the father and son here are not inherited, they are ClassLoader
implementations of abstract classes, and therefore all contain a ClassLoader parent
member variable that points to its parent loader. The delegated relationship here can also be used as an agent .
Parent Delegated source Code implementation
Then let's take a look at the code, which loadClass
is the ClassLoader
core method of class loading in an abstract class.
protectedClass<?>LoadClass(String name,BooleanResolvethrowsclassnotfoundexception {synchronized(Getclassloadinglock (name)) {//Jobenga is loaded before, the cache is taken directly, the native method is implementedClass C = findloadedclass (name);if(c = =NULL) {Try{The parent loader is first delegated to load if(Parent! =NULL) {//Note here recursive callc = Parent.loadclass (name,false); }Else{//bootstrap is inaccessible, so the parent of ext must be null //At this time directly with the native method call startup class load load, if not found, throw exceptionc = findbootstrapclassornull (name); } }Catch(ClassNotFoundException e) {//ClassNotFoundException not processed, only as exit recursion}if(c = =NULL) {//If the parent loader fails to load then look within the scope of this ClassLoader ///Findclass The class file is found, the DefineClass method is called to import the bytecode into the method area, and the results are cachedc = findclass (name); } }//Whether parsing, default false if(resolve) {Resolveclass (c); }returnC } }
It can be seen that the nature of the so-called parental assignment is the two-sentence recursive code:
ifnull) { false);}
The load succeeds in getting the class object C, the failure throws the exception and the previous method catches and ignores with catch, and then the current class loader findClass()
operation, so repeated.
Note
1. For security reasons, the bootstrap startup ClassLoader only loads classes that begin with the package named Java, javax, Sun , and so on
2. Class loading will enter the link stage , which contains validation, preparation, parsing, resolve parameters determine whether to perform the parsing phase, the JVM specification does not strictly specify the execution time of the stage
3. Because the lookup cache is used first findLoadedClass()
, the same class will only be loaded once
User-defined class loader
When you write your own class implementation ClassLoader
, it is the user-defined class loader. When instantiating a custom ClassLoader, the system ClassLoader () is adopted by defaultwithout specifying the parent ClassLoader (without passing the parent ClassLoader to the constructor). The corresponding parameterless default constructor is implemented as follows:
protectedClassLoader() { this(checkCreateClassLoader(), getSystemClassLoader());}
It will call the parameter constructor and getSystemClassLoader()
pass in the System class loader as the parent. So the user-defined class loader can also get the class object loaded by the 3 ClassLoader in a parent-delegated way.
When implementing a custom class loader, you should not override loadClass()
it unless you do not need a parental delegation mechanism. The logic to override is the findClass()
way the class is loaded.
The class object obtained using the custom class loader gets the instance through Newinstance () to compare whether two class objects with the same class fully qualified name are the same, depending on whether the same classloader loaded them , that is, calling defineClass()
Instead of the class loader that was previously delegated.
Analysis of common methods
java.lang.Class
Methods of the Object
Class<?> forName(……)
This is a common way to load a class manually, Class
with two overloads in the class:
public static Class<?> forName(String className)
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
There may be a question here, which class loader is used by default to load the first method? Let's take a look at the implementation:
publicstaticforName(String className) throws ClassNotFoundException { // 使用native方法获取调用类的Class对象 Class<?> caller = Reflection.getCallerClass(); returntrue, ClassLoader.getClassLoader(caller), caller);}
Where getClassLoader(caller)
you set up the class loader you are using, continue to see its implementation:
static ClassLoader getClassLoader(Class<?> caller) { ifnull) { returnnull; } return caller.getClassLoader0(); }}
The official note for this code is the class loader that returns caller, which means that the native method getClassLoader0()
returns the caller's ClassLoader. That is, assuming that the Class A is executed forName(String className)
, then the ClassLoader used is to load the classloader of a.
Tips
forName0()
The essence is still ClassLoader
called loadClass()
to load the class.
ClassLoader getClassLoader()
This method is used to get the class loader that loads a class object, but it is obtained through an instance or class object:
(new A()).getClass().getClassLoader()
A.class.getClassLoader()
A variety of methods for obtaining class information
After a class object is reflected, the class information is obtained through the following methods:
Field[] getDeclaredFields()
Class[] getDeclaredClasses()
Method[] getDeclaredMethods()
等等
For details, please refer to Javadoc or view source code
java.lang.ClassLoader
Methods of the Object
ClassLoader getParent()
Get parent ClassLoader
Class loadClass(String)
Explicitly call this method for class loading, passing in the class fully qualified name
URL getResource(String)
Gets the resource locator with the given name. The resource can be any data, and the name must be separated by a "/" path name. The actual invocation findResource()
method, the method is not implemented, requires subclass inheritance implementation.
InputStream getResourceAsStream(String)
Gets the InputStream input stream that can read the resource, which is actually called after getting to the URL using the above method url.openStream()
InputStream.
ClassLoader getSystemClassLoader()
This is a static method that ClassLoader.getSystemClassLoader()
can be obtained through the system ClassLoader Appclassloader, regardless of the calling class. The implementation is described in the last section.
URLClassLoader Overview
ClassLoader
is just an abstract class, many methods are empty need to implement themselves, such as findClass()
, and findResource()
so on. Java provides java.net.URLClassLoader
this implementation class for use with a variety of application scenarios.
First of all, the AppClassLoader
ExtClassLoader
URLClassLoader
subclass mentioned before, the custom class loader recommends inheriting it directly.
Look at the description in Javadoc:
The ClassLoader is used to load classes and resources from a set of URL paths (pointing to a jar package or directory). The Convention uses URLs that end with '/' to represent directories. If it does not end with that character, the URL is considered to point to a jar file.
constructor function
URLClassLoader
Accept an array of URLs as parameters, which will load the required classes under these provided paths, and the corresponding primary constructors have
public URLClassLoader(URL[] urls)
URLClassLoader(URL[] urls, ClassLoader parent)
getURLs()
Method
Use URL[] getURLs()
the method to get the URL path, reference code:
public static void main(String[] args) { URL[] urls = ((URLClassLoader)ClassLoader.getSystemClassLoader()).getURLs(); for (URL: urls) { System.out.println(url); }}// file:/D:/Workbench/Test/bin/
Load mode
In, findClass()
it uses classes URLClassPath
in the class Loader
to load class files and resources. The class URLClassPath
defines the implementation of two Loader
classes, respectively FileLoader
JarLoader
, and classes, which are used to load classes and resources in the directory, as the name implies, and the latter is the classes and resources loaded in the jar package. Loader
class is already implemented by default getResource()
, which is to load the jar package from the network URL address and then use JarLoader
to complete subsequent loads, while the two implementation classes simply override the method.
You may want to ask how URLClassPath
is the choice to use the right one Loader
? The answer is--it depends on the URL format. Take a look at the core code that has been cut down below, easy to understand.
PrivateLoaderGetloader(FinalUrl url) {String s = url.getfile ();//At the end of "/", if the URL protocol is "file" then use Fileloader to load the local file //Otherwise load the network URL using the default loader if(s! =NULL&& S.endswith ("/")) {if("File". Equals (Url.getprotocol ()))return NewFileloader (URL);Else return NewLoader (URL); }Else{//Non-"/" End uses Jarloader return NewJarloader (URL, Jarhandler, lmap); }}
getSystemClassLoader()
Implementation of the method
getSystemClassLoader()
The traced source can be found to be essentially sun.misc.Launcher
retrieving its member variables through an instance loader
. So loader
when did this assignment go to the value? Let's take a look at its constructor (the irrelevant content is truncated):
Public Launcher() {Extclassloader extclassloader;Try{//Create and Initialize extension class loader ExtclassloaderExtclassloader = Extclassloader.getextclassloader (); }Catch(IOException IOException) {Throw NewInternalerror ("Could not create extension class loader"); }Try{//Create and initialize the system ClassLoader Appclassloader and assign to loaderLoader = Appclassloader.getappclassloader (Extclassloader); }Catch(IOException Ioexception1) {Throw NewInternalerror ("Could not create application class loader"); }//The thread context ClassLoader is set to Appclassloader by default //related information see another blog postThread.CurrentThread (). Setcontextclassloader (loader); }
You can see Launcher
that the initialization was created ExtClassLoader
and the AppClassLoader
thread context class loader is set AppClassLoader
to the default settings . Although I did not see the source of the JVM, I speculated that the JVM might have created Launcher
the extensions and the system ClassLoader by creating an instance, and the launch (Bootstrap) class loader was created by calling the local method.
Obviously, the getSystemClassLoader()
return of the loader is AppClassLoader
correct, here we also found the thread context class loader assignment, specifically about the thread context class loader learning please refer to another blog post.
Summarize
There are not many scenarios where you can write your own classloader, but the above analysis of the ClassLoader will at least give you an idea of the underlying implementation mechanism of the JVM and how you are familiar with the implementation of reflection. My personal style is to know the reason why, in my understanding of the scope of knowledge I am interested to study. Before always spend a whole period of time to chew on the difficulty after the ignored, after work to develop this often note the habit, his summary after the comb is indeed better than to look at other people's article to come deeper and more thorough, hope to keep!
Java ClassLoader Incomplete analysis