👌如何破坏双亲委派模型

👌如何破坏双亲委派模型

题目详细答案

自定义类加载器

通过创建自定义类加载器并覆盖loadClass方法,可以实现不同于双亲委派机制的类加载策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CustomClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
// 如果是特定的类,不使用双亲委派机制
if (name.startsWith("com.example")) {
// 自定义加载逻辑
byte[] classData = getClassData(name);
if (classData != null) {
return defineClass(name, classData, 0, classData.length);
}
}
// 否则,使用默认的双亲委派机制
return super.loadClass(name);
}

private byte[] getClassData(String className) {
// 实现类加载的逻辑,例如从文件系统或网络加载类字节码
return null;
}
}

通过反射机制

利用反射机制直接操作类加载器的父类加载器,绕过双亲委派机制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.lang.reflect.Field;

public class BreakParentDelegation {
public static void main(String[] args) throws Exception {
CustomClassLoader customClassLoader = new CustomClassLoader();
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();

// 获取系统类加载器的父类加载器(扩展类加载器)
Field parentField = ClassLoader.class.getDeclaredField("parent");
parentField.setAccessible(true);
parentField.set(appClassLoader, customClassLoader);

// 现在系统类加载器的父类加载器被替换为自定义类加载器
Class<?> clazz = Class.forName("com.example.MyClass", true, appClassLoader);
System.out.println(clazz.getClassLoader());
}
}

OSGi 框架

OSGi 框架提供了一种模块化的类加载机制,允许每个模块(Bundle)有自己的类加载器,从而可以打破双亲委派机制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// OSGi 中的 BundleActivator 示例
public class MyBundleActivator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
// 在 OSGi 环境中,每个 Bundle 有自己的类加载器
ClassLoader bundleClassLoader = getClass().getClassLoader();
Class<?> clazz = bundleClassLoader.loadClass("com.example.MyClass");
System.out.println(clazz.getClassLoader());
}

@Override
public void stop(BundleContext context) throws Exception {
// 停止 Bundle 时的清理工作
}
}

使用 SPI(Service Provider Interface)

某些服务提供者接口的实现中,可能需要打破双亲委派机制来加载服务实现类。

1
2
3
4
5
6
7
8
9
10
import java.util.ServiceLoader;

public class SPIDemo {
public static void main(String[] args) {
ServiceLoader<MyService> loader = ServiceLoader.load(MyService.class);
for (MyService service : loader) {
service.execute();
}
}
}

在META-INF/services目录下创建一个文件,文件名为接口的全限定名,文件内容为实现类的全限定名。通过这种方式,JVM 会使用Thread.contextClassLoader来加载服务实现类,从而可以打破双亲委派机制。

 wechat
天生我才必有用