自定义类的加载器

自定义类加载器在Java中扮演着关键角色,如隔离加载类、修改加载方式和扩展加载源。常见场景包括模块隔离和动态获取类定义信息。实现时通常继承ClassLoader并重写findClass()方法,遵循双亲委派模型。注意不同加载器间的类型转换需在同一加载器下进行。
摘要由CSDN通过智能技术生成

一 为什么要自定义类加载器?

  • 隔离加载类

    在某些框架内进行中间件与应用的模块隔离,把类加载到不同的环境。比如:阿里内某容器框架通过自定义类加载器确保应用中依赖的 jar 包不会影响到中间件运行时使用的 jar 包。再比如:Tomcat 这类 Web 应用服务器,内部自定义了好几种类加载器,用于隔离同一个 Web 应用服务器上的不同应用程序。

  • 修改类加载的方式

    类的加载模型并非强制,除 Bootstrap 外,其他的加载并非一定要引入,或者根据实际情况在某个时间点进行按需进行动态加载。

  • 扩展加载源

    比如从数据库、网络、甚至是电视机机顶盒进行加载。

  • 防止源码泄漏

    Java 代码容易被编译和篡改,可以进行编译加密。那么类加载也需要自定义,还原加密的字节码。

1 常见的场景

  • 实现类似进程内隔离,类加载器实际上用作不同的命名空间,以提供类似容器、模块化的效果。例如,两个模块依赖于某个类库的不同版本,如果分别被不同的容器加载,就可以互不干扰。这个方面的集大成者是 JavaEE 和 OSGI、JPMS 等框架。

  • 应用需要从不同的数据源获取类定义信息,例如网络数据源,而不是本地文件系统。或者是需要自己操纵字节码,动态修改或者生成类型。

2 注意

在一般情况下,使用不同的类加载器去加载不同的功能模块,会提高应用程序的安全性。但是,如果涉及 Java 类型转换,则加载器反而容易产生不美好的事情。在做 Java 类型转换时,只有两个类型都是由同一个加载器所加载,才能进行类型转换,否则转换时会发生异常。

二 实现方式

Java 提供了抽象类 java.lang.ClassLoader,所有用户自定义的类加载器都应该继承 ClassLoader 类。

在自定义 ClassLoader 的子类时候,我们常见的会有两种做法。

  • 方式一:重写 loadClass() 方法

  • 方式二:重写 findclass() 方法

1 对比

  • 这两种方法本质上差不多,毕竟 loadClass() 也会调用 findClass(),但是从逻辑上讲我们最好不要直接修改 loadClass() 的内部逻辑。建议的做法是只在 findClass() 里重写自定义类的加载方法,根据参数指定类的名字,返回对应的 Class 对象的引用。

  • loadclass() 这个方法是实现双亲委派模型逻辑的地方,擅自修改这个方法会导致模型被破坏,容易造成问题。因此我们最好是在双亲委派模型框架内进行小范围的改动,不破坏原有的稳定结构。同时,也避免了自己重写 loadClass() 方法的过程中必须写双亲委托的重复代码,从代码的复用性来看,不直接修改这个方法始终是比较好的选择。

  • 当编写好自定义类加载器后,便可以在程序中调用 loadClass() 方法来实现类加载操作。

2 说明

  • 其父类加载器是系统类加载器

  • JVM 中的所有类加载都会使用 java.lang.ClassLoader.loadClass(String) 接口(自定义类加载器并重写 java.lang.ClassLoader.loadClass(String)接口的除外),连 JDK 的核心类库也不能例外。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值