双亲委派模型

好处

双亲委派模型是 Java 类加载器机制中的一种设计思想,它将类加载操作委派给父类加载器,只有在父类加载器无法加载某个类时才由子类加载器来加载。双亲委派模型的好处包括:

  1. 隔离性:通过将类加载操作委派给父类加载器,每个类加载器都有自己的命名空间,可以确保不同类加载器加载的类彼此隔离,防止类之间的冲突和混淆。

  2. 避免重复加载:双亲委派模型可以避免同一个类被多个类加载器重复加载。当一个类被加载后,它会被缓存到父类加载器的命名空间中,后续相同的类加载请求会直接返回缓存的类,避免了重复加载和内存浪费。

  3. 安全性:通过双亲委派模型,Java 运行时环境可以确保核心类库的安全性和一致性。核心类库由启动类加载器加载,其他类都委托给父类加载器加载,从而确保了核心类库的完整性和安全性。

  4. 减少类加载器冲突:双亲委派模型使得类加载器之间的关系变得清晰和有序,可以有效地避免类加载器冲突和类重复加载的问题。每个类加载器都有自己的父类加载器,通过委派机制保证了类加载的有序性和一致性。

有哪些框架用到了双亲委派模型

  • Java 核心类库:Java 核心类库是由启动类加载器加载的,它们的加载遵循双亲委派模型。

  • Servlet 容器:例如 Tomcat、Jetty 等 Servlet 容器通常会使用双亲委派模型加载 Web 应用程序中的类和资源。

  • Spring 框架:Spring 框架是一个广泛使用的 Java 开发框架,它的核心模块和依赖库都会受到双亲委派模型的影响。

  • Hibernate ORM:Hibernate 是一个流行的对象关系映射框架,它也会利用 Java 类加载器的双亲委派模型来加载实体类和持久化对象。

  • Apache Commons 系列:Apache Commons 是一系列常用的 Java 工具库,例如 Apache Commons Lang、Apache Commons IO 等,它们也会使用到双亲委派模型。

  • JUnit 测试框架:JUnit 是一个流行的 Java 单元测试框架,它的加载过程也会受到双亲委派模型的影响。

  • Log4j 日志框架:Log4j 是一个常用的 Java 日志框架,它的加载过程也会遵循双亲委派模型。

如何打破双亲委派机制

双亲委派机制是一种 Java 类加载机制,它保证了 Java 类加载的一致性和安全性。在这种机制下,当一个类加载器收到类加载请求时,它会首先将请求委派给父类加载器进行加载,如果父类加载器无法完成加载任务,才会由当前类加载器进行加载。这个机制确保了 Java 核心类库(如 java.lang.Object)不会被重写或篡改。

虽然双亲委派机制有其重要性,但在某些特殊场景下,可能需要打破这种机制。例如,当需要加载不同版本的库时,或者进行插件化开发时,可能需要自定义类加载器来打破双亲委派机制。以下是几种打破双亲委派机制的方法:

1. 自定义类加载器

通过自定义类加载器,可以在 loadClass 方法中控制类的加载顺序,从而绕过双亲委派机制。

public class CustomClassLoader extends ClassLoader {
    
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // 先尝试自己加载
        try {
            byte[] classData = getClassData(name);
            if (classData != null) {
                return defineClass(name, classData, 0, classData.length);
            }
        } catch (Exception e) {
            // Ignore and fallback to parent
        }
        
        // 如果加载失败,委派给父类加载器
        return super.loadClass(name, resolve);
    }

    private byte[] getClassData(String className) {
        // 从文件或其他来源获取类数据
        return null;  // 示例中返回 null
    }
}

2. 使用 Thread.getContextClassLoader()

在某些情况下,可以通过设置线程上下文类加载器来绕过双亲委派机制。线程上下文类加载器可以通过 Thread.setContextClassLoader() 来设置,并通过 Thread.getContextClassLoader() 来获取。

Thread.currentThread().setContextClassLoader(new CustomClassLoader());

3. 重写 findClass 方法

自定义类加载器时,可以重写 findClass 方法,而不是 loadClass 方法。这种方法通常在需要更细粒度控制类加载过程时使用。

public class CustomClassLoader extends ClassLoader {
    
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = getClassData(name);
        if (classData == null) {
            throw new ClassNotFoundException();
        }
        return defineClass(name, classData, 0, classData.length);
    }

    private byte[] getClassData(String className) {
        // 从文件或其他来源获取类数据
        return null;  // 示例中返回 null
    }
}

4. 使用 URLClassLoader

URLClassLoader 是一种现成的类加载器,允许从 URL 指定的路径加载类。在某些场景下,可以利用 URLClassLoader 来实现类加载的灵活性,打破双亲委派机制。

URL[] urls = {new URL("file:///path/to/classes/")};
URLClassLoader urlClassLoader = new URLClassLoader(urls, null);  // null 代表不使用父类加载器
Class<?> clazz = urlClassLoader.loadClass("com.example.MyClass");

注意事项

  • 打破双亲委派机制可能会带来类加载的安全性和一致性问题,需要谨慎处理。
  • 在使用自定义类加载器时,需要考虑类的重复加载、类冲突等问题。
  • 尽量在插件系统、应用容器等需要隔离不同版本类库的场景下使用自定义类加载器。

通过以上方法,可以在必要时打破双亲委派机制,从而实现更灵活的类加载策略。

  • 18
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清石小猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值