双亲委派机制详解
双亲委派机制详解
双亲委派机制(Parent Delegation Model)是Java类加载器的核心设计模式,用于保证Java程序运行的安全性和稳定性。
1. 类加载器层次结构
四种类加载器
-
Bootstrap ClassLoader(启动类加载器)
- C++实现,是JVM的一部分
- 加载
<JAVA_HOME>/lib
目录下的核心类库 - 如
rt.jar
、resources.jar
等
-
Extension ClassLoader(扩展类加载器)
- Java实现,父类加载器为Bootstrap ClassLoader
- 加载
<JAVA_HOME>/lib/ext
目录下的扩展类库
-
Application ClassLoader(应用程序类加载器)
- Java实现,父类加载器为Extension ClassLoader
- 加载ClassPath路径下的类库
- 是程序默认的类加载器
-
Custom ClassLoader(自定义类加载器)
- 继承
ClassLoader
类实现的自定义加载器 - 父类加载器为Application ClassLoader
- 继承
2. 双亲委派机制工作原理
工作流程
- 当一个类加载器收到类加载请求时,不会立即加载
- 先委托给父类加载器尝试加载
- 父类加载器无法加载时,才由自己加载
// ClassLoader.loadClass()方法的核心逻辑
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 检查类是否已被加载
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
// 委派给父类加载器
c = parent.loadClass(name, false);
} else {
// 委派给Bootstrap ClassLoader
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 父类加载器无法加载
}
if (c == null) {
// 自己加载类
c = findClass(name);
}
}
return c;
}
}
类加载流程示例
当应用程序加载java.lang.String
类时:
Application ClassLoader
收到加载请求- 委派给
Extension ClassLoader
Extension ClassLoader
继续委派给Bootstrap ClassLoader
Bootstrap ClassLoader
在核心类库中找到并加载String
类- 返回加载结果,避免了重复加载
3. 双亲委派机制的优势
安全性保障
- 防止核心类库被篡改
- 避免用户自定义的
java.lang.Object
类被加载 - 保证Java程序的稳定运行
// 即使用户自定义了java.lang.String类
// 也会被Bootstrap ClassLoader加载的String类替代
public class String {
// 这个类不会被加载执行
public static void main(String[] args) {
System.out.println("Custom String class");
}
}
避免重复加载
- 相同类只会被加载一次
- 节省内存空间
- 提高加载效率
命名空间隔离
- 不同类加载器加载的类相互隔离
- 支持应用服务器部署多个应用
4. 双亲委派机制的破坏
破坏场景
-
JNDI服务
- 需要Bootstrap ClassLoader加载的类调用用户代码
- 使用线程上下文类加载器(Thread Context ClassLoader)解决
-
OSGi框架
- 需要灵活的类加载策略
- 实现模块化和热部署
-
热部署和热替换
- 开发工具需要重新加载修改的类
- 应用服务器需要更新应用
线程上下文类加载器
// 获取当前线程的上下文类加载器
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
// 设置线程上下文类加载器
Thread.currentThread().setContextClassLoader(customClassLoader);
5. 自定义类加载器
实现方式
public class CustomClassLoader extends ClassLoader {
private String classPath;
public CustomClassLoader(String classPath) {
this.classPath = classPath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = loadClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
} else {
return defineClass(name, classData, 0, classData.length);
}
}
private byte[] loadClassData(String className) {
// 实现类文件的读取逻辑
String fileName = classPath + File.separatorChar +
className.replace('.', File.separatorChar) + ".class";
try {
FileInputStream fis = new FileInputStream(fileName);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b;
while ((b = fis.read()) != -1) {
baos.write(b);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
6. 实际应用场景
应用服务器
- Tomcat、WebLogic等应用服务器使用自定义类加载器
- 实现应用间的类隔离
- 支持热部署功能
插件化架构
- Eclipse等IDE的插件系统
- OSGi框架的模块化设计
动态加载
- 数据库驱动加载
- Web应用的Servlet加载