什么是双亲委派机制
双亲委派机制(Parent Delegation Mechanism)是Java中的一种类加载机制。在Java中,类加载器负责加载类的字节码并创建对应的Class对象。双亲委派机制是指当一个类加载器收到类加载请求时,它会先将该请求委派给它的父类加载器去尝试加载。只有当父类加载器无法加载该类时,子类加载器才会尝试加载。
这种机制的设计目的是为了保证类的加载是有序的,避免重复加载同一个类。Java中的类加载器形成了一个层次结构,根加载器(Bootstrap ClassLoader)位于最顶层,它负责加载Java核心类库。其他加载器如扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader)都有各自的加载范围和职责。通过双亲委派机制,可以确保类在被加载时,先从上层的加载器开始查找,逐级向下,直到找到所需的类或者无法找到为止。
这种机制的好处是可以避免类的重复加载,提高了类加载的效率和安全性。同时,它也为Java提供了一种扩展机制,允许开发人员自定义类加载器,实现特定的加载策略。

双亲委派机制的原理
双亲委派机制是Java中的一种类加载机制。其原理如下:
-
当Java程序需要加载一个类时,首先会委托给当前类加载器的父类加载器进行加载。
-
父类加载器会按照相同的方式尝试加载该类。如果父类加载器能够成功加载该类,则加载过程结束。
-
如果父类加载器无法加载该类,则会将加载请求再次委托给它的父类加载器,直到达到顶层的引导类加载器。
-
引导类加载器是Java虚拟机内置的类加载器,它负责加载核心类库,如java.lang包下的类。
-
如果引导类加载器也无法加载该类,则会回到初始的类加载器,尝试使用自身的加载机制加载该类。
-
如果自身的加载机制仍然无法加载该类,则会抛出ClassNotFoundException异常。
通过这种双亲委派的机制,Java实现了类加载的层次结构。它可以确保类的加载是有序的,避免了重复加载和类的冲突。同时,它也提供了一种安全机制,防止恶意代码的加载和执行。
通过代码讲解双亲委派机制
首先,我们需要自定义一个类加载器,继承自ClassLoader类,并重写loadClass()方法。在loadClass()方法中,我们可以实现自己的类加载逻辑。
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
// 首先尝试使用父类加载器加载类
try {
return super.loadClass(name);
} catch (ClassNotFoundException e) {
// 如果父类加载器无法加载类,则自己加载类
return findClass(name);
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 在这里实现自己的类加载逻辑,例如从特定位置加载类文件
// 这里只是一个示例,实际实现需要根据具体需求进行处理
byte[] classData = loadClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
}
return defineClass(name, classData, 0, classData.length);
}
private byte[] loadClassData(String name) {
// 在这里实现加载类文件的逻辑,返回类文件的字节数组
// 这里只是一个示例,实际实现需要根据具体需求进行处理
try {
FileInputStream fis = new FileInputStream(name + ".class");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
fis.close();
bos.close();
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
// 创建自定义类加载器
MyClassLoader classLoader = new MyClassLoader();
try {
// 使用自定义类加载器
Class<?> clazz = classLoader.loadClass("classloader.MyClassLoader");
System.out.println("Class loaded: " + clazz.getName());
} catch (ClassNotFoundException e) {
System.out.println("Class not found");
}
}
}
我们创建了一个自定义的类加载器MyClassLoader,并使用它来加载名为"MyClass"的类。在loadClass()方法中,我们首先尝试使用父类加载器加载类,如果父类加载器无法加载类,则自己加载类。
通过运行上面代码,我们可以观察到双亲委派机制的工作原理。首先,自定义类加载器会尝试委托给父类加载器加载类,如果父类加载器能够成功加载类,则加载过程结束。如果父类加载器无法加载类,则会回到自己的加载机制,尝试使用自身的类加载逻辑加载类。
打破双亲委派机制
既然双亲委派机制是保证java程序安全性稳定运行的一种机制,那么可以进行打破吗?
当然可以。
在ClassLoader中有两个方法loadClass()、findClass()。
-
loadClass()方法主要是委派给父类加载器进行加载,是一个委托方法
-
findClass()用于查找类文件并生成Class对象的方法,是一个进行加载的方法。
因此得出结论:想破坏双亲委派机制的话只需要重写loadClass方法。进行自定义类加载的时候通常会重写findClass方法。
双亲委派机制的优缺点
优点:
-
避免重复加载:通过委派给父类加载器,可以避免同一个类被多次加载,提高了加载效率。
-
安全性:通过双亲委派机制,核心类库由根加载器加载,可以确保核心类库的安全性,防止恶意代码替换核心类。
-
扩展性:开发人员可以自定义类加载器,实现特定的加载策略,从而扩展Java的类加载机制。
缺点:
-
灵活性受限:双亲委派机制对于某些特殊的类加载需求可能过于严格,限制了加载器的灵活性。
-
破坏隔离性:如果自定义类加载器不遵循双亲委派机制,可能会破坏类加载的隔离性,导致类冲突或安全性问题。
-
不适合动态更新:由于类加载器在加载类时会先检查父加载器是否已加载,因此在动态更新类时可能会出现问题,需要额外的处理。
总体而言,双亲委派机制通过层次结构和委派机制提供了一种有序、安全的类加载方式,但也存在一些限制和不适用的情况。
2111

被折叠的 条评论
为什么被折叠?



