简体   繁体   English

如何从不同的 jar 中订购 spring @PostConstruct 调用?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM