在 Spring 6 中从 JPMS 模块读取类时出现问题

问题描述 投票:0回答:1

我有一个带有图层树的 JPMS 应用程序。在

Layer C
上,我需要创建 Spring 上下文,而 Spring 框架位于
Layer B
:

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 [email protected]/org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:178)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:415)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:287)
    at [email protected]/org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:344)
    at [email protected]/org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:115)
    at [email protected]/org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:779)
    at [email protected]/org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:597)
        ....
Caused by: java.io.FileNotFoundException: class path resource [org/springframework/context/ApplicationContextAware.class] cannot be opened because it does not exist
    at [email protected]/org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:211)
    at [email protected]/org.springframework.core.type.classreading.SimpleMetadataReader.getClassReader(SimpleMetadataReader.java:54)
    at [email protected]/org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:48)
    at [email protected]/org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:103)
    at [email protected]/org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:122)
    at [email protected]/org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:81)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.asSourceClass(ConfigurationClassParser.java:613)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser$SourceClass.getInterfaces(ConfigurationClassParser.java:939)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.processInterfaces(ConfigurationClassParser.java:379)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:325)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:243)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:188)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:297)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:243)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:196)
    at [email protected]/org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:164)
    ... 16 more

据我了解(我可能是错的)Spring 使用其他一些类加载器。谁能说一下怎么解决吗

java spring classloader java-module spring-context
1个回答
0
投票

我解决了问题。

Spring 通过

getResourceAsStream()
加载类,默认情况下使用
ClassPathResource
classLoader.getResourceAsStream(this.absolutePath)
。但是,它不适用于 JPMS 应用程序。为了使其工作,需要使用
ModuleResource
(在 Spring 6.1 中添加)而不是
ClassPathResource

因此,有必要创建将使用

ResourceLoader
并将其设置为上下文的自定义
ModuleResource

var iocContext = new  AnnotationConfigApplicationContext();
...
var myModuleResourceLoader = ....
iocContext.setResourceLoader(myModuleResourceLoader);
iocContext.refresh();
© www.soinside.com 2019 - 2024. All rights reserved.