V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
leegoo
V2EX  ›  程序员

SpringBoot 怎么做到在 web 容器启动之前做点 xx 事情?

  •  
  •   leegoo · 2023-03-13 11:49:58 +08:00 · 2048 次点击
    这是一个创建于 621 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前有很多初始化方法都实现了 org.springframework.boot.ApplicationRunner#run ,同时该应用也提供了 web 功能。

    目前发现一个问题。该应用在没有完全执行完 org.springframework.boot.ApplicationRunner#run 方法后就会可以访问 HTTP 接口。导致接口响应结果与实际业务结果不符。

    查询了一下初始化方法类可以实现ApplicationPreparedEvent接口,确实在 Web 容器启动前调用了。但是不能获取到bean

    想问下大家还有其他的方式吗。

    9 条回复    2023-03-13 15:56:22 +08:00
    javahuang
        1
    javahuang  
       2023-03-13 12:23:28 +08:00
    @EventListener(ApplicationReadyEvent.class)
    话说这种问题不是 google 来的更快吗
    selca
        2
    selca  
       2023-03-13 12:28:06 +08:00
    ```java
    // Allows post-processing of the bean factory in context subclasses.
    postProcessBeanFactory(beanFactory);

    StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);

    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);
    beanPostProcess.end();

    // Initialize message source for this context.
    initMessageSource();

    // Initialize event multicaster for this context.
    initApplicationEventMulticaster();

    // Initialize other special beans in specific context subclasses.
    onRefresh();

    // Check for listener beans and register them.
    registerListeners();

    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);

    // Last step: publish corresponding event.
    finishRefresh();
    ```
    看了下,web 容器在 onRefresh()阶段初始化的,可以看下这里前几个阶段有没有可以操作的
    lry
        3
    lry  
       2023-03-13 13:03:03 +08:00
    需要做的事情是啥?需要拿到什么 bean ?
    通用的可以试试当做完事情之后再注册服务
    anc95
        4
    anc95  
       2023-03-13 13:13:49 +08:00
    可以通过实现 Spring 的接口 org.springframework.boot.ApplicationRunner 或 org.springframework.boot.CommandLineRunner 来在 web 容器启动之前执行一些操作。这些接口的实现类会在 Spring Boot 应用启动时被自动运行。

    ApplicationRunner 的 run() 方法会在 Spring 应用启动完成后被调用,而 CommandLineRunner 的 run(String... args) 方法会在 Spring 应用启动时被调用,这两个接口的返回值类型都是 void 。

    例如,以下代码实现了一个 CommandLineRunner 接口:

    @Component
    public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
    System.out.println("执行 MyCommandLineRunner");
    }
    }
    当 Spring Boot 应用启动时,MyCommandLineRunner 中的 run() 方法会被调用,并输出 执行 MyCommandLineRunner 。
    leegoo
        5
    leegoo  
    OP
       2023-03-13 14:02:06 +08:00
    @javahuang 谢谢你的答案,我试了一下在 META-INF/spring.factories 添加了`org.springframework.context.ApplicationListener=xxxListener`
    `xxxListener 类里面实现了 ApplicationListener<ApplicationReadyEvent>`。SpringBoot 启动时可以调到`xxxListener`类,不过依然获取不到 bean 对象
    leegoo
        6
    leegoo  
    OP
       2023-03-13 14:04:28 +08:00
    获取应该说。在 xxxListener 执行时。controller 已经提前执行了。
    shellic
        7
    shellic  
       2023-03-13 14:26:37 +08:00
    WebServerInitializedEvent
    cheng6563
        8
    cheng6563  
       2023-03-13 15:06:57 +08:00
    直接 @PostConstruct 就行了啊
    ThreeK
        9
    ThreeK  
       2023-03-13 15:56:22 +08:00   ❤️ 1
    建议直接百度张 spring boot 注入启动的流程图,确定下自己的代码想何时触发,然后再看自己需要实现那个钩子函数就行。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2647 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 11:12 · PVG 19:12 · LAX 03:12 · JFK 06:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.