Spring DeferredImportSelector 运行 在任何配置之前
Spring DeferredImportSelector run before any Configurations
我正在尝试创建类似@Enable...自动配置的东西。我想为具有广泛 spring 配置的自定义库创建这样的注释,但需要提供 2 个 beans,并基于这些初始化各种上下文。它确实初始化了数组中返回的所有@configuration classes 中的bean,但我还想根据已经注册的bean 执行一些自定义配置逻辑。现在的javadoc
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ImportSelector.html
表示
ImportSelectors are usually processed in the same way as regular @Import annotations, however, it is also possible to defer selection of imports until all @Configuration classes have been processed (see DeferredImportSelector for details).
所以我求助于 DeferredImportSelector,因为在所有 @Configuration bean 之后据说 Selector 是 运行,所以我可以做条件 Bean。现在 javadoc 在这里很清楚 (https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/DeferredImportSelector.html)
A variation of ImportSelector that runs after all @Configuration beans have been processed. This type of selector can be particularly useful when the selected imports are @Conditional
所以这对我来说是完美的。好吧,直到事实证明无论我做什么,导入选择器 selectImports 方法都是 运行 总是在所有 @Configuration beans 之前。
我发现也许主 @Configuration bean 总是最后一个,javadoc 实际上提到了所有导入的 @Configuration bean。看来也并非如此。我一直在使用调试器检查优先级,但这是我做的测试代码,它非常简单:
除系统输出外什么都不做的导入选择器:
public class TestImportSelector implements DeferredImportSelector{
@Override
public String[] selectImports(AnnotationMetadata arg0) {
System.out.println("ImportSelector");
return new String[0];
}
}
配置class(导入以检查提到的任何想法是否有效)
@Configuration
public class ImportedTestContext {
@Bean
public String testBeanString2(){
System.out.println("bean2");
return "string2";
}
}
主要上下文class(也尝试交换导入的classes)
@Configuration
@Import({TestImportSelector.class, ImportedTestContext.class})
public class TestMainContext {
@Bean
public String testBeanString(){
System.out.println("bean1");
return "string";
}
}
最后是我的主class
public class Test {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(TestMainContext.class);
}
}
Sooo,作为你运行的主力。你总是得到相同的输出
ImportSelector
bean2
bean1
导入选择器无论如何总是第一个。另外,我试图像 javadoc 所说的那样乱用 Ordered 接口
Implementations can also extend the Ordered interface or use the Order annotation to indicate a precedence against other DeferredImportSelectors
但似乎甚至没有调用 getOrder 方法。好吧,这可能是因为它说它只会再次检查其他 DeferredImportSelectors(并且有 none 但值得尝试)
我已经使用 spring-context 4.3.2.RELEASE 完成了此操作,因为这是我的项目中使用的,但只是为了确保也使用 5.0.5.RELEASE 进行了测试。
完全一样的结果。
所以我相信我不明白关于 ImportSelector、DeferredImportSelector、spring 的某些事情,或者 javadoc 有可能没有说实话或者我误解了它....
如果有任何帮助或建议,我将不胜感激....
只是说清楚:基于那个 DeferredImportSelector,我希望它实现 BeanFactoryAware(这部分有效,Spring 确实注入了 BeanFactory),它会检查已经定义了哪些 bean(就像那些有趣的测试string beans),并基于它告诉 spring 应该加载哪些额外的配置。基于 javadoc,这就是它的用途......
看起来 DeferredImportSelector
的文档有点不清楚。 运行 测试和检查代码后,发现 deferred
是 Import
而不是 ImportSelector
.
因此,如果您使用 DeferredImportSelector
,您可以 select 配置 class(es) 导入将是 deferred
.
A selectImports
方法将正常执行 - 在配置文件期间 resolving/parsing,所以 - 使用 BeanFactory
检查其他 bean 的定义是否已经加载肯定不是一个好主意(有些人可能还没有)。
最好的方法是将此逻辑放入 @Conditional
注释系列(在目标配置 class 内)并确保在所有用户定义的配置之后处理它。
我正在尝试创建类似@Enable...自动配置的东西。我想为具有广泛 spring 配置的自定义库创建这样的注释,但需要提供 2 个 beans,并基于这些初始化各种上下文。它确实初始化了数组中返回的所有@configuration classes 中的bean,但我还想根据已经注册的bean 执行一些自定义配置逻辑。现在的javadoc https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ImportSelector.html
表示
ImportSelectors are usually processed in the same way as regular @Import annotations, however, it is also possible to defer selection of imports until all @Configuration classes have been processed (see DeferredImportSelector for details).
所以我求助于 DeferredImportSelector,因为在所有 @Configuration bean 之后据说 Selector 是 运行,所以我可以做条件 Bean。现在 javadoc 在这里很清楚 (https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/DeferredImportSelector.html)
A variation of ImportSelector that runs after all @Configuration beans have been processed. This type of selector can be particularly useful when the selected imports are @Conditional
所以这对我来说是完美的。好吧,直到事实证明无论我做什么,导入选择器 selectImports 方法都是 运行 总是在所有 @Configuration beans 之前。
我发现也许主 @Configuration bean 总是最后一个,javadoc 实际上提到了所有导入的 @Configuration bean。看来也并非如此。我一直在使用调试器检查优先级,但这是我做的测试代码,它非常简单:
除系统输出外什么都不做的导入选择器:
public class TestImportSelector implements DeferredImportSelector{
@Override
public String[] selectImports(AnnotationMetadata arg0) {
System.out.println("ImportSelector");
return new String[0];
}
}
配置class(导入以检查提到的任何想法是否有效)
@Configuration
public class ImportedTestContext {
@Bean
public String testBeanString2(){
System.out.println("bean2");
return "string2";
}
}
主要上下文class(也尝试交换导入的classes)
@Configuration
@Import({TestImportSelector.class, ImportedTestContext.class})
public class TestMainContext {
@Bean
public String testBeanString(){
System.out.println("bean1");
return "string";
}
}
最后是我的主class
public class Test {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(TestMainContext.class);
}
}
Sooo,作为你运行的主力。你总是得到相同的输出
ImportSelector
bean2
bean1
导入选择器无论如何总是第一个。另外,我试图像 javadoc 所说的那样乱用 Ordered 接口
Implementations can also extend the Ordered interface or use the Order annotation to indicate a precedence against other DeferredImportSelectors
但似乎甚至没有调用 getOrder 方法。好吧,这可能是因为它说它只会再次检查其他 DeferredImportSelectors(并且有 none 但值得尝试)
我已经使用 spring-context 4.3.2.RELEASE 完成了此操作,因为这是我的项目中使用的,但只是为了确保也使用 5.0.5.RELEASE 进行了测试。 完全一样的结果。
所以我相信我不明白关于 ImportSelector、DeferredImportSelector、spring 的某些事情,或者 javadoc 有可能没有说实话或者我误解了它....
如果有任何帮助或建议,我将不胜感激....
只是说清楚:基于那个 DeferredImportSelector,我希望它实现 BeanFactoryAware(这部分有效,Spring 确实注入了 BeanFactory),它会检查已经定义了哪些 bean(就像那些有趣的测试string beans),并基于它告诉 spring 应该加载哪些额外的配置。基于 javadoc,这就是它的用途......
看起来 DeferredImportSelector
的文档有点不清楚。 运行 测试和检查代码后,发现 deferred
是 Import
而不是 ImportSelector
.
因此,如果您使用 DeferredImportSelector
,您可以 select 配置 class(es) 导入将是 deferred
.
A selectImports
方法将正常执行 - 在配置文件期间 resolving/parsing,所以 - 使用 BeanFactory
检查其他 bean 的定义是否已经加载肯定不是一个好主意(有些人可能还没有)。
最好的方法是将此逻辑放入 @Conditional
注释系列(在目标配置 class 内)并确保在所有用户定义的配置之后处理它。