You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决JDK 16及更高版本中反射操作失效的问题?

Java 16下反射调用URLClassLoader#addURL失效的解决方案

问题原因

Java 9引入模块系统后,JDK内部API的访问权限逐步收紧,到Java 16默认开启了全量强封装限制。URLClassLoader属于java.base模块下的java.net包,非公共方法的反射访问会被模块机制拦截,导致setAccessible生效失败。


可行方案

方案1:添加JVM启动参数临时兼容

无需修改业务代码,直接在启动命令中添加参数放开对应包的访问权限即可:

--add-opens java.base/java.net=ALL-UNNAMED

如果你的应用使用了命名模块,将ALL-UNNAMED替换为你自己的模块名即可。该方案适合需要快速兼容旧代码、暂时无法重构的场景。

方案2:提前收集所有Jar路径构造实例(无动态加载需求时推荐)

如果可以提前获取所有需要加载的Jar路径,直接把所有路径传入URLClassLoader的构造方法,完全不需要用到反射:

try {
    URL jarUrl = new File("C:/external-folder/my.jar").toURI().toURL();
    // 所有需要加载的Jar路径都放入该数组
    URL[] urls = new URL[]{jarUrl};
    URLClassLoader classLoader = new URLClassLoader(urls);
    // 后续使用classLoader加载目标类即可
} catch (Exception exc) {
    exc.printStackTrace();
}

方案3:自定义类加载器暴露addURL方法(有动态加载需求时推荐)

URLClassLoader的addURL本身是protected修饰的方法,我们可以自定义类继承URLClassLoader,直接将该方法暴露为公共方法,完全符合模块系统规范,不需要额外启动参数,也没有反射开销:

  1. 首先实现自定义类加载器:
import java.net.URL;
import java.net.URLClassLoader;

public class DynamicURLClassLoader extends URLClassLoader {
    public DynamicURLClassLoader(URL[] urls) {
        super(urls);
    }

    @Override
    public void addURL(URL url) {
        super.addURL(url);
    }
}
  1. 替换原有反射逻辑:
try {
    DynamicURLClassLoader classLoader = new DynamicURLClassLoader(new URL[]{});
    classLoader.addURL(new File("C:/external-folder/my.jar").toURI().toURL());
    // 后续使用classLoader加载目标类即可
} catch (Exception exc) {
    exc.printStackTrace();
}

注意:如果你的场景需要把外部Jar添加到系统类加载器的类路径中,优先建议调整逻辑使用自定义类加载器加载外部类,避免修改系统类加载器导致类冲突问题,确实需要修改系统类加载器的场景可以使用方案1兼容。

内容的提问来源于stack exchange,提问作者JJB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 16:30:02