Spring Boot启动后运行代码


211

我想在我的spring-boot应用开始监视目录更改后运行代码。

我尝试运行新线程,但此时@Autowired尚未设置服务。

我已经能够找到ApplicationPreparedEvent,它会在设置@Autowired注释之前触发。理想情况下,一旦应用程序准备处理http请求,我希望触发该事件。

Spring Boot中启动应用程序后,是否有更好的事件可以使用,或者有更好的代码运行方式?



Spring Boot提供了两个接口ApplicationRunner和CommandLineRunner,可以在您希望在Spring Boot启动后运行代码时使用它们。您可以参考本文的实现示例-jhooq.com/applicationrunner-spring-boot
Rahul

Answers:


121

尝试:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application extends SpringBootServletInitializer {

    @SuppressWarnings("resource")
    public static void main(final String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

        context.getBean(Table.class).fillWithTestdata(); // <-- here
    }
}

6
当您将应用程序作为war文件部署到外部tomcat时,此方法不起作用。它仅适用于嵌入式的tomcat
SAURABH

不,它不起作用。但是在这种使用情况下,我更喜欢使用更明确的方法@Component。请参阅来自@cjstehno的答案,以使其在war文件中起作用。
安东·贝索诺夫,2016年

320

就这么简单:

@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
    System.out.println("hello world, I have just started up");
}

在版本上测试 1.5.1.RELEASE


7
谢谢。这使我的代码可以正常工作而无需进行任何更改。再次感谢您提供如此简单的答案。这也可以与@RequestMapping注释一起使用,没有任何问题。
Harshit

16
也可能有人希望使用@EventListener(ContextRefreshedEvent.class)它,它在创建bean之后但在服务器启动之前被触发。它可以用于在任何请求到达服务器之前执行活动。
neeraj

3
@neeraj,问题是有关在Spring Boot启动后运行代码。如果使用ContextRefreshedEvent,它也会在每次刷新后运行。
cahen

4
在Spring Boot 2.0.5.RELEASE上测试
ritesh '19

2
在2.2.2版本上测试。它完美地工作。这种解决方案节省了我的时间。
阿飞

96

您是否尝试过ApplicationReadyEvent?

@Component
public class ApplicationStartup 
implements ApplicationListener<ApplicationReadyEvent> {

  /**
   * This event is executed as late as conceivably possible to indicate that 
   * the application is ready to service requests.
   */
  @Override
  public void onApplicationEvent(final ApplicationReadyEvent event) {

    // here your code ...

    return;
  }
}

来自以下网址的代码:http//blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/

这是文档中提到的有关启动事件的内容:

...

应用程序事件在您的应用程序运行时按以下顺序发送:

ApplicationStartedEvent在运行开始时发送,但在除侦听器和初始化程序的注册之外的任何处理之前发送。

当已知要在上下文中使用的环境时,但在创建上下文之前,将发送ApplicationEnvironmentPreparedEvent。

在刷新开始之前,但在加载bean定义之后,发送了ApplicationPreparedEvent。

刷新后,将发送ApplicationReadyEvent,并且已处理所有相关的回调,以指示应用程序已准备好处理请求。

如果启动时发生异常,则发送ApplicationFailedEvent。

...


11
作为替代方案,您可以@EventListener在Bean方法上使用批注来执行此操作,将要钩住的类事件作为参数传递。
Padilo

2
这应该是选择的答案。
varun113

2
在spring-boot 2中,这已经发生了变化。如果您是从1.x移植并使用ApplicationStartedEvent,则现在需要ApplicationStartingEvent。
安迪·布朗

这绝对好用,我认为是最好的方法。
AVINASH SHRIMALI

你是最好的
-ancm

83

为什么不创建一个在初始化时启动监视器的Bean,例如:

@Component
public class Monitor {
    @Autowired private SomeService service

    @PostConstruct
    public void init(){
        // start your monitoring in here
    }
}

init直到对bean完成任何自动装配后,该方法才会被调用。


14
有时@PostConstruct开火太早。例如,当使用Spring Cloud Stream Kafka时,@PostConstruct在应用程序绑定到Kafka之前触发。Dave Syer的解决方案更好,因为它可以及时触发。
Elnur Abdurrakhimov

9
@PostConstruct发生在初始化期间,而不是之后。尽管在某些情况下这很有用,但是如果您想 Spring Boot启动运行,那不是正确的答案。例如,虽然@PostConstruct尚未完成,但没有端点可用。
cahen

63

“ Spring Boot”方法是使用CommandLineRunner。只需添加这种类型的豆,就可以了。在Spring 4.1(Boot 1.2)中,还有SmartInitializingBean一个在所有初始化之后获得回调的函数。还有SmartLifecycle(从Spring 3开始)。


有什么例子吗?是否可以在应用运行后通过命令行在任意时刻执行Bean?
Emilio

5
不知道“任意时刻”是什么意思。Spring Boot用户指南和示例包含使用CommandLineRunner(和较新版本ApplicationRunner)的示例:docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/…
Dave Syer 2015年

我发现,生命周期是在应用程序的启动/停止阶段执行异步任务的首选选项,并且我试图找出CommandLineRunner和InitializingBeans之间的其他差异,但找不到任何相关信息。
saljuama 2015年

3
几个常用的使用示例代码CommandLineRunner
Alexey Simonov '18

41

您可以使用扩展类ApplicationRunner,覆盖run()方法并在其中添加代码。

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {

        //code goes here

    }
}

在Spring Boot中完美。但是在类具有ApplicationScope时,两次调用了run()方法。因此,以上的PostConstruct方法效果更好。
山姆

26

ApplicationReadyEvent仅在您要执行的任务不需要正确的服务器操作时才真正有用。启动异步任务以监视某些内容的更改就是一个很好的例子。

但是,如果您的服务器在任务完成之前处于“未就绪”状态,则最好实施,SmartInitializingSingleton因为您将在获得回调之前在打开REST端口和服务器开始营业。

不要试图将@PostConstruct其仅执行一次。当您发现它被多次调用时,您会得到一个粗鲁的惊喜……


这应该是选择的答案。正如@Andy指出的那样,在打开端口之前会调用SmartInitializingSingleton。
Srikanth

24

带有弹簧配置:

@Configuration
public class ProjectConfiguration {
    private static final Logger log = 
   LoggerFactory.getLogger(ProjectConfiguration.class);

   @EventListener(ApplicationReadyEvent.class)
   public void doSomethingAfterStartup() {
    log.info("hello world, I have just started up");
  }
}

12

SmartInitializingSingleton在春季> 4.1时使用Bean

@Bean
public SmartInitializingSingleton importProcessor() {
    return () -> {
        doStuff();
    };

}

作为替代方案,CommandLineRunner可以实现Bean或使用注释Bean方法@PostConstruct


我可以在该方法中要求自动装配依赖吗?我想设置配置文件
LppEdd

7

提供一个Dave Syer答案的示例,它的工作原理很吸引人:

@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(CommandLineAppStartupRunner.class);

    @Override
    public void run(String...args) throws Exception {
        logger.info("Application started with command-line arguments: {} . \n To kill this application, press Ctrl + C.", Arrays.toString(args));
    }
}

7

试试这个,当应用程序上下文完全启动时,它将运行您的代码。

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent arg0) {
                // EXECUTE YOUR CODE HERE 
    }
}

6

我真的很喜欢EventListener@cahen(https://stackoverflow.com/a/44923402/9122660)关于使用注释的建议,因为它非常干净。不幸的是,我无法在Spring + Kotlin设置中使用它。对于Kotlin起作用的是将类添加为方法参数:

@EventListener 
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
    System.out.println("hello world, I have just started up");
}

将其放在spring boot应用程序类中,不要随机放在外面@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
Ahmed na

您不需要将其放在@SpringBootApplication类中。任何配置类都可以
George Marin

5

在Spring Boot应用程序启动后执行代码块的最佳方法是使用PostConstruct批注,或者也可以使用命令行运行器。

1.使用PostConstruct批注

@Configuration
public class InitialDataConfiguration {

    @PostConstruct
    public void postConstruct() {
        System.out.println("Started after Spring boot application !");
    }

}

2.使用命令行流道bean

@Configuration
public class InitialDataConfiguration {

    @Bean
    CommandLineRunner runner() {
        return args -> {
            System.out.println("CommandLineRunner running in the UnsplashApplication class...");
        };
    }
}

3

只需为Spring Boot应用程序实现CommandLineRunner。您需要实现run方法,

public classs SpringBootApplication implements CommandLineRunner{

    @Override
        public void run(String... arg0) throws Exception {
        // write your logic here 

        }
}

0

使用CommandLineRunner或ApplicationRunner的最佳方法两者之间的唯一区别是run()方法CommandLineRunner接受字符串数组,而ApplicationRunner接受ApplicationArugument。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.