ClassLoader plus Living Example
First, the class loader and parents delegate mechanism introduced
In the JVM, the class is loaded into the virtual machine process comprises three steps, i.e. loading, connected and initialized. The loading of this process, by the class loader is ClassLoader
loaded, the class loader is inherently responsible for this duty.
Java itself provides us with several types of class loader, boot class loader Bootstrap ClassLoader
, the extension class loader Extension ClassLoader
, the application class loader App ClassLoader
, in addition to three kinds of the above, we can define our own class loader, then we just need to inherited ClassLoader
class, override its findClass()
methods can be.
Of course, sometimes, you think not you think that when we use a custom class loader to load the class path ClassPath
a at class
a file, and then call the Class
object getClassLoader()
when the method, we find that the class loader loads the class is not our custom loader, as to why? It will be mentioned below. The figure is the JVM class loader mechanism
-
1, the boot class loader
Bootstrap ClassLoader
Start class loader is responsible for
%JRE_HOME/lib/
the relevant class files in the directory, for examplert.jar
,tools.jar
and so on, for example, ourString
class is stored inrt.jar
, the the loader isBootstrap ClassLoader
-
2, extension classloader
Extension ClassLoader
Extension class loader is responsible for
%JRE_HOME/lib/ext
the relevant class files in the directory, for examplert.jar
,tools.jar
etc. -
3, the application class loader
App ClassLoader
Application class loader responsible for loading in the application classpath
class
files.
When it comes to issues of class path, we explain that the class path java refers to the value of the system environment variables we configured: CLASSPATH
, but not limited to this value. Our local print small series at first classpath
values:
.;D:\development\jdk\lib\dt.jar;D:\development\jdk\lib\tools.jar;
You will find that this is simply not the tools we use it in the catalog, then JVM
it is how we loaded into eclipse
the classes written it? The answer is that eclipse
has helped us somehow everything.
Below we give an example, look at String
what kind of class loader is:
System.out.println(String.class.getClassLoader());
The above sentence code output null
. why? Because if a class is to be Bootstrap ClassLoader
, or Extension ClassLoader
loading, getClassLoader()
a predetermined output null
. And because String
class exists rt.jar
, it will be Bootstrap ClassLoader
loaded, so output null
.
Turning to the class loader, we have to say that class parents delegate mechanism, stating parents delegate mechanism, Xiao Bian summarized in one sentence:
If the custom loader loader has a parent P P1, then it will be loaded before loading the delegate tasks to his father P1, if there is a parent loader P1 P2, it will load the task assigned to P2, if the topmost further Bootstrap ClassLoader load less, then again against the order loaded until a class is loaded ~~
Second, the ClassLoader
class features introduced
-
1. Each
Therefore, we can alwaysClass
instance contains aClassLoader
referenceClass
objectgetClassLoader()
method to get its class loader. Of course, as above said, if a class is to beBootstrap ClassLoader
, orExtension ClassLoader
loading,getClassLoader()
a predetermined outputnull
. This is a point we need to pay attention. -
2, for an array type
[]
objects, they are not by the class loaderClassLoader
to be loaded, but the Java virtual machine created automatically as needed. Through an array type ofClass
objectgetClassLoader()
as the return value of the method with an array of elements used inside the class loader, but if the array element type is the originalint
Han, thegetClassLoader()
method returnsnull
// sun.misc.Launcher$AppClassLoader@73d16e93 ClassLoaderTest[] array = new ClassLoaderTest[5]; System.out.println(array.getClass().getClassLoader()); // null int[] intArray = new int[3]; System.out.println(intArray.getClass().getClassLoader()); 复制代码
-
3, we can inherit
ClassLoader
classes to implement your own class loader
/**
* 自定义类加载器
* @Author jiawei huang
* @Since 2019年8月7日
* @Version 1.0
*/
public class MyClassLoader extends ClassLoader {
// 如果我们从其他地方进行加载,我们可以指定路径
private String classpath;
public MyClassLoader(String classPath) {
classpath = classPath;
}
public MyClassLoader() {
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class clazz = null;
// 获取该class文件字节码数组
byte[] classData = getClassData();
if (classData != null) {
// 将class的字节码数组转换成Class类的实例
clazz = defineClass(name, classData, 0, classData.length);
}
return clazz;
}
private byte[] getClassData() {
byte[] bytes = null;
File file = new File(classpath);
if (file.exists()) {
// 从文件中读取class字节数据
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(file);
out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int size = 0;
while ((size = in.read(buffer)) != -1) {
out.write(buffer, 0, size);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
bytes = out.toByteArray();
}
return bytes;
}
}
复制代码
Suppose we ex
have a package under the path Main.java
, we take a look at the following output:
A.java
MyClassLoader loader = new MyClassLoader();
Class<?> clazzClass = loader.loadClass("ex.Main");
// 1
System.out.println(clazzClass.getClassLoader());
复制代码
Above 1
at the output sun.misc.Launcher$AppClassLoader@73d16e93
, we might ask, obviously I was using my own class loader to load ex.Main
Yeah, why was the output of AppClassLoader
the class loader it? In fact, this is the parents delegate mechanism, MyClassLoader
the task is loaded to its parent loader App ClassLoader
, just ex.Main
turn in the class path, so App ClassLoader
after loading directly returned.
-
4, a class throughout the life cycle will only be loaded once, and only once
-
5, support for parallel load loader called parallel loaders, but only if we have the custom loader initialization, call the
ClassLoader.registerAsParallelCapable();
method to register themselves, how to do it? We take a look atURLClassLoader
the source code.
static {
// 注册自己
ClassLoader.registerAsParallelCapable();
}
复制代码
- 6, in the case of commission model is not strictly hierarchical, custom class loader needs to have the ability to parallel, or class loading can lead to deadlock because the loader lock has been held in the class loading process.
We look at the details ClassLoader
of the loadClass()
method Source:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 这里有个锁
synchronized (getClassLoadingLock(name)) {
1、先检查这个名称的类是否已经被加载过,如果是,就不再加载了,这也印证了我们第4点说的一个类只会被加载一次
Class<?> c = findLoadedClass(name);
// 2、如果该类没有被加载,那么就进行加载
if (c == null) {
long t0 = System.nanoTime();
try {
// 3、如果存在父加载器,就进行委派,这就是双亲委派机制的原理
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// 4、去`Bootstrap classloader`加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
// 5、如果3,4都没有加载到,那就执行我们自定义的classloader,这也是为什么我们要重写findClass方法的原因所在
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
复制代码
- 7, we can not only to classes loaded from the file system, we can also be from the network
class
load files, accessbyte[]
, and then byClassLoader
thedefineClass()
willbyte[]
be converted intoClass
an object, and finally throughClass.newInstance()
to turn it into Java objects ~ ~ ~
ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();
复制代码
Third, SpringBoot
in the constructor why add ClassLoader
parameters?
Because the initialization process, the load()
method needs to load class files from different places.
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
复制代码