版权声明:欢迎转载交流,声明出处即可。体能状态先于精神状态,习惯先于决心,聚焦先于喜好 ——Bestcxx https://blog.csdn.net/bestcxx/article/details/90513633
文章目录
JVM 类加载机制
/**
* 获取类加载器的测试方法
*/
@Test
public void test2() {
//获取Test类的类加载器 sun.misc.Launcher$AppClassLoader@4dc63996
ClassLoader c = Test.class.getClassLoader();
System.out.println(c);
//获取c这个类加载器的父类加载器 sun.misc.Launcher$ExtClassLoader@28a418fc
ClassLoader c1 = c.getParent();
System.out.println(c1);
// getClassLoader() returning null indicates the bootstrap ClassLoader
//获取c1这个类加载器的父类加载器 ,null,因为Bootstrp loader是C++编写的,依java的观点来看,逻辑上并不存在Bootstrap Loader的类实体
//根装载器:Bootstrp loader
//用C++语言写的,它是在Java虚拟机启动后初始化的,主要负责加载%JAVA_HOME%/jre/lib,
//* -Xbootclasspath参数指定的路径以及%JAVA_HOME%/jre/classes中的类。
ClassLoader c2 = c1.getParent();
System.out.println(c2);
//获取系统默认的ClassLoader sun.misc.Launcher$AppClassLoader@4dc63996
ClassLoader c3=ClassLoader.getSystemClassLoader();
System.out.println(c3);
//获取创建当前线程的类加载器
ClassLoader c4= Thread.currentThread().getContextClassLoader();
System.out.println(c4);
}
双亲委派模型
简单说就是,先由自己的父类加载需要的类,一直向上传递,如果没有再由自己加载
类加载器可以重写,但是核心类是不允许使用自己的类加载器加载的,比如 jdk 核心包 java.lang.String ,只允许 bootstrap ClassLoader 进行加载
Spring 类加载机制
入口 AbstractApplicationContext.prepareBeanFactory
beanFactory.setBeanClassLoader(getClassLoader());
DefaultResourceLoader.getClassLoader()
org.springframework.core.io.DefaultResourceLoader
/**
* Return the ClassLoader to load class path resources with.
* <p>Will get passed to ClassPathResource's constructor for all
* ClassPathResource objects created by this resource loader.
* @see ClassPathResource
*/
@Override
public ClassLoader getClassLoader() {
//如果指定了类加载器就返回指定的类加载器,否则获取线程类加载器->不存在就获取ClassUtils类加载器-> 不存在就获取系统默认类加载器
return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
}
ClassUtils.getDefaultClassLoader()
org.springframework.util.ClassUtils.getDefaultClassLoader()
看中文注释
/**
* Return the default ClassLoader to use: typically the thread context
* ClassLoader, if available; the ClassLoader that loaded the ClassUtils
* class will be used as fallback.
* <p>Call this method if you intend to use the thread context ClassLoader
* in a scenario where you clearly prefer a non-null ClassLoader reference:
* for example, for class path resource loading (but not necessarily for
* {@code Class.forName}, which accepts a {@code null} ClassLoader
* reference as well).
* @return the default ClassLoader (only {@code null} if even the system
* ClassLoader isn't accessible)
* @see Thread#getContextClassLoader()
* @see ClassLoader#getSystemClassLoader()
*/
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
//获取当前线程类加载器
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
//如果线程类加载器为null
if (cl == null) {
// No thread context class loader -> use class loader of this class.
//获取当前类的类加载器
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
//getClassLoader() 为 null 说明是 bootstrap ClassLoader 类加载器,该加载器为 C++ 编写,故从Java 角度看是 null
try {
//获取当前系统的类加载器
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}