[英]How to order spring @PostConstruct calls from different jars?
I can't find a way to order the execution of post-init methods in Spring.我找不到在 Spring 中对 post-init 方法的执行进行排序的方法。
I need to order these methods because one is populating data used by the others init methods.我需要订购这些方法,因为其中一个正在填充其他 init 方法使用的数据。
In the spring context I have a test component that is used only to init an in-memory db when it is needed.在 spring 上下文中,我有一个测试组件,仅用于在需要时初始化内存数据库。 This component is defined in a dependency.
该组件是在依赖项中定义的。
@Profile({"INMEMORY"})
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class InMemoryDatabaseInitializer {
@PostConstruct
private void setupInMemoryDb() {
// create db schema and populate it with test data into the inmemory db
}
}
I have a configuration object that is tested with this in memory profile and that perform a post construct operation that checks some flags in the db:我有一个配置对象,在内存配置文件中对此进行了测试,并执行检查数据库中的一些标志的后构造操作:
@Configuration
public class MyConfiguration {
@PostConstruct
private void checkDbFlags() {
// perform some SQL selects using JPA
}
}
With this setup, the MyConfiguration instance is resolved first and the post-init method checkDbFlags() is called before the in memory db is initialized by the post-init method setupInMemoryDb() and the test crashes.使用此设置,首先解析 MyConfiguration 实例,并在内存数据库由 post-init 方法 setupInMemoryDb() 初始化之前调用 post-init 方法 checkDbFlags() 并且测试崩溃。
I have also tried to move the db init method in the constructor this way:我还尝试以这种方式在构造函数中移动 db init 方法:
@Profile({"INMEMORY"})
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class InMemoryDatabaseInitializer {
public InMemoryDatabaseInitializer() {
// perform some SQL selects using JPA
}
}
but even in this case, the Configuration post-init method checkDbFlags() is called first and crashs because the db structure is not yet installed.但即使在这种情况下,配置 post-init 方法 checkDbFlags() 被首先调用并崩溃,因为尚未安装 db 结构。
I don't want to add a direct dependency between MyConfiguration and the InMemoryDatabaseInitializer, so I hoped that the @Order in front of the @Configuration would do the trick, but it doesn't.我不想在 MyConfiguration 和 InMemoryDatabaseInitializer 之间添加直接依赖关系,所以我希望 @Configuration 前面的 @Order 可以解决问题,但事实并非如此。 The issue occurs only when the post-init method for the db setup is located in another jar than the one using the db.
仅当 db 设置的 post-init 方法位于另一个 jar 中而不是使用 db 的 jar 时,才会出现此问题。
A demo application showing this behavior is available here: https://github.com/guame/so_spring_postinit_issue此处提供了显示此行为的演示应用程序: https : //github.com/guame/so_spring_postinit_issue
You can run the com.example.demo.DemoApplicationTests to highlight the issue.您可以运行 com.example.demo.DemoApplicationTests 来突出显示问题。 Here is a sample log of the current execution:
这是当前执行的示例日志:
2020-01-07 09:38:47.035 com.example.demo.DemoApplicationTests : Starting DemoApplicationTests
2020-01-07 09:38:47.036 com.example.demo.DemoApplicationTests : The following profiles are active: INMEMORY
2020-01-07 09:38:47.410 com.example.demo.DbInitializerFromApp : add DATA_FROM_APP into db
2020-01-07 09:38:47.415 yConfig$$EnhancerBySpringCGLIB$$1806b9e8 : checking the flags
2020-01-07 09:38:47.415 yConfig$$EnhancerBySpringCGLIB$$1806b9e8 : checkFlag from current app: DATA_FROM_APP
2020-01-07 09:38:47.415 yConfig$$EnhancerBySpringCGLIB$$1806b9e8 : checkFlag from dependencies jar: null
2020-01-07 09:38:47.418 c.example.demodata.DbInitializerFromJar : add DATA_FROM_DEPENDENCY into db
2020-01-07 09:38:47.476 com.example.demo.DemoApplicationTests : Started DemoApplicationTests in 0.802 seconds (JVM running for 1.942)
The flow is correct for the Initializer located in the application, but not for the Initializer located in a dependency.该流程对于位于应用程序中的 Initializer 是正确的,但对于位于依赖项中的 Initializer 则不正确。
How can I force the order of the post-init methods so the resolution of some of my initializing beans are resolved before the other even if they are located in dependencies ?我如何强制 post-init 方法的顺序,以便我的一些初始化 bean 的解析在另一个之前解析,即使它们位于依赖项中?
Using ApplicationListener or EventListener you can get notified when the complete Spring context has been initialized.使用 ApplicationListener 或 EventListener 可以在完整的 Spring 上下文初始化时得到通知。 If it's sufficent call your
checkDbFlags()
method from there...如果它足够从那里调用您的
checkDbFlags()
方法......
@Component
public class StartupApplicationListenerExample implements
ApplicationListener<ContextRefreshedEvent> {
@Override public void onApplicationEvent(ContextRefreshedEvent event) {
checkDbFlags();
}
}
https://www.baeldung.com/running-setup-logic-on-startup-in-spring https://www.baeldung.com/running-setup-logic-on-startup-in-spring
我认为 @DependsOn 注释在这种情况下可能会有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.