文章目录
- 1、双亲委派机制
- 2、Java代码中去主动加载一个类
- 3、“父”加载器
- 4、Q & A
- 5、打破双亲委派机制
1、双亲委派机制
JVM中有多个类加载器,某个类A,到底该由谁去加载 ⇒ 双亲委派机制
该机制的作用:
- 保证类加载的安全性:避免用户自定义一个java.lang.String恶意替换JDK的核心类库里的String类
- 避免重复加载:避免同一个类被多次加载,提高效率
该机制的内容是,当一个类加载接收到加载类的任务时:
- 自底向上查找是否已经被父加载器加载过,有则直接返回
- 若没被加载,再自顶向下进行加载
从下往上查找是否被加载过,没有则委派给父类加载器:
若全都没有被加载过,则从启动类加载器开始加载,当要加载的类不在启动类加载器的加载范围时,往下走到扩展类加载器,以此类推。
这种机制的好处是:控制了加载优先级,一个类优先去由启动类加载器去尝试加载
2、Java代码中去主动加载一个类
方式一:Class.forName( ),使用当前类的加载器去加载
方式二:classLoader对象.loadClass( ),使用指定的加载器对象去加载
public class LoaderTest {
public static void main(String[] args) throws ClassNotFoundException, IOException {
//自己写的类
ClassLoader classLoader = TestJvm.class.getClassLoader();
System.out.println(classLoader);
//尝试用应用类加载器去加载String类
Class<?> clazz = classLoader.loadClass("java.lang.String");
System.out.println(clazz.getClassLoader());
}
}
运行结果的null,即说明还是用的启动类加载器加载的String,体现了双亲委派机制:
3、“父”加载器
双亲委派机制里的父加载器,这个父,不是Java继承的那个父,只是类加载器对象中有个成员变量叫parent,是上级关系,不是有继承关系。
应用程序加载器的parent属性为扩展类加载器,而扩展类加载器的parent为null,这是由于Java代码中没法拿到启动类加载器的对象,因此赋值为null。启动类加载器用c++编写,没有父加载器
Arthas工具查看类加载器的父子关系:
classloader -t
4、Q & A
Q:双亲委派机制?
A:
- 某个类加载器加载一个类时,向上查找、向下加载,有加载过则直接返回,到顶层类加载器也没被加载过,再向下加载
- 应用程序类加载器的父加载器是扩展类加载器,扩展类加载器的父加载器是启动类加载器,启动类加载器无父加载器
- 好处是避免恶意替换JDK核心类以及避免重复加载
Q:如果一个类被三种类加载器都无法加载?
A:返回ClassNotFountException
Q:一个类重复出现在三个类加载器的范围,由谁来加载
A:由启动类加载器,其优先级最高
Q:自己的项目新建一个java.lang.String,能否被加载
A:否,会由启动类加载器加载JDK/rt.jar包下的String类
5、打破双亲委派机制
该机制下,向上查找、向下加载,如果有两个全类名相同的类,但内容不同,就只会有一个被加载。如Tomcat上运行多个web应用,其中两个web应用里都有com.plat.MyServlet类,则双亲委派机制下,后者不会被加载:
Tomcat使用了自定义类加载器来实现应用之间类的隔离。每一个应用会有一个独立的类加载器加载对应的类。
想打破类的双亲委派机制,方法有: