我有一个带有图层树的 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 使用其他一些类加载器。谁能说一下怎么解决吗
我解决了问题。
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();