我正在使用 Java 11 和 Spring 开发 JavaFX 应用程序。应用程序模块使用 与自定义 JRE 捆绑在一起jlink
,它只允许将命名模块包含在包中。由于 Spring 不提供命名模块,而是依赖自动模块来实现 Java 9 模块系统支持,因此我使用moditect将模块描述符 ( module-info.java
) 添加到 Spring JAR。
编译、编译jlink
和执行应用程序没有任何问题。@Component
但是,尽管我的AppConfig
类带有注释,但 Spring 没有检测到我的应用程序的任何类注释@ComponentScan
:
@Configuration
@ComponentScan
public class AppConfig {
}
在Main
中,我创建了一个AnnotationConfigApplicationContext
基于AppConfig
并打印所有已注册的 bean 以及类路径上可用的资源:
public class Main extends Application {
private ConfigurableApplicationContext applicationContext;
public static void main(String[] args) {
launch(args);
}
@Override
public void init() {
applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
}
@Override
public void start(Stage mainWindow) throws IOException {
System.out.println("Printing beans: " + applicationContext.getBeanDefinitionNames().length);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
System.out.println(Arrays.toString(resolver.getResources("classpath*:com/myapp/**/*.class")));
}
@Override
public void stop() {
applicationContext.stop();
}
}
如果我使用 IntelliJ 运行应用程序,则会PathMatchingResourcePatternResolver
在类路径上找到我的所有类(我猜是因为 IntelliJ 使用类路径而不是模块路径运行应用程序)。因此,通过组件扫描检测所有组件并创建相应的 bean:
Printing beans: 8
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalPersistenceAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig
com.myapp.services.UserServiceImpl
com.myapp.services.BookingServiceImpl
[file [/Users/user/myapp/target/classes/com/myapp/AppConfig.class], file [/Users/user/myapp/target/classes/com/myapp/Main.class], file [/Users/user/myapp/target/classes/com/myapp/services/UserService.class], file [/Users/user/myapp/target/classes/com/myapp/services/UserServiceImpl.class], file [/Users/user/myapp/target/classes/com/myapp/services/BookingService.class], file [/Users/user/myapp/target/classes/com/myapp/services/BookingServiceImpl.class]]
但是,如果我通过jlink
'ed 包运行应用程序,即在使用模块路径的自定义 JRE 上,Spring 无法检测到我的任何类:
Printing beans: 5
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
appConfig
[]
PathMatchingResourcePatternResolver
没有找到任何类(因为现在所有内容都位于模块路径上),并且组件扫描没有实例化一个 bean。
如果我将组件类手动导入AppConfig
,则 bean 会正确创建并通过以下方式注入@Autowired
:
@Configuration
@Import({
com.myapp.service.UserServiceImpl.class,
com.myapp.service.BookingServiceImpl.class
})
public class AppConfig {
}
为什么 Spring 在使用时能够创建 bean @Import
,但无法通过 检测它们@ComponentScan
?如何通过 解决我的组件@ComponentScan
?