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

JPMS分层应用中Spring 6上下文创建失败问题求助

JPMS分层应用中Spring上下文创建的类加载器问题

问题场景

我有一个带分层结构的JPMS应用,Spring框架位于Layer B,需要在Layer C中创建Spring上下文:

boot layer
  |- Layer B with Spring framework.
       |- Layer C where I need to create my context

组件代码

@Component
public class ApplicationContextHolder implements ApplicationContextAware {

    private static ConfigurableApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextHolder.applicationContext = (ConfigurableApplicationContext) applicationContext;
    }

    public static ConfigurableApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

配置类代码

@Configuration
@ComponentScan(basePackageClasses = {
    ApplicationContextHolder.class
})
public class ContextConfig {

}

创建上下文的代码

System.out.println("ThreadContextClassLoadere:" + Thread.currentThread().getContextClassLoader());
    System.out.println("This classLoader:" + this.getClass().getClassLoader());
    var clazz = this.getClass().getClassLoader().loadClass("org.springframework.context.ApplicationContextAware");
    System.out.println("RESULT:" + clazz);
    iocContext = new  AnnotationConfigApplicationContext();
    iocContext.register(ContextConfig.class);
    iocContext.setClassLoader(this.getClass().getClassLoader());
    iocContext.refresh();

执行结果

ThreadContextClassLoadere:jdk.internal.loader.Loader@63fcbf75
This classLoader:jdk.internal.loader.Loader@63fcbf75
RESULT:interface org.springframework.context.ApplicationContextAware

Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.foo.ContextConfig]
    at spring.context@6.0.13/org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:178)
    ....
Caused by: java.io.FileNotFoundException: class path resource [org/springframework/context/ApplicationContextAware.class] cannot be opened because it does not exist
    ....

我猜测Spring使用了其他类加载器,请问该如何解决这个问题?


解决方案

1. 修正JPMS模块依赖与分层可见性

在Layer C的module-info.java中,必须明确声明对Spring核心模块的依赖,同时确保Layer B是Layer C的可读层:

module com.foo.layerC {
    requires spring.context;
    requires spring.beans;
    // 按需添加其他Spring模块依赖
}

启动应用时,通过JPMS参数确保分层间的模块访问权限,比如使用--add-modules指定Spring模块,或通过分层配置让Layer C能访问Layer B的内容。

2. 提前设置Spring上下文的类加载器

当前代码是先创建上下文再设置类加载器,但Spring在初始化早期就会用到类加载器,导致时机滞后。需调整顺序:

ClassLoader currentClassLoader = this.getClass().getClassLoader();
// 方式1:构造时直接传入类加载器
iocContext = new AnnotationConfigApplicationContext(currentClassLoader);
iocContext.register(ContextConfig.class);
iocContext.refresh();

// 方式2:无参构造后立即设置类加载器(必须在register/refresh之前)
iocContext = new AnnotationConfigApplicationContext();
iocContext.setClassLoader(currentClassLoader);
iocContext.register(ContextConfig.class);
iocContext.refresh();

3. 统一线程上下文类加载器

Spring部分资源加载逻辑会依赖线程上下文类加载器,显式将其与当前类加载器对齐:

ClassLoader currentClassLoader = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(currentClassLoader);

iocContext = new AnnotationConfigApplicationContext(currentClassLoader);
iocContext.register(ContextConfig.class);
iocContext.refresh();

4. 调整模块开放权限

JPMS的模块封装机制可能导致Spring无法扫描或访问你的组件类,在Layer C的module-info.java中开放对应包给Spring:

module com.foo.layerC {
    // 允许Spring框架扫描并反射你的组件类
    opens com.foo to spring.context;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 13:32:24