Spring Boot启动后运行代码

ste*_*ers 168 java spring spring-boot

我想在我的spring-boot应用程序开始监视目录以进行更改后运行代码.

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

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

是否有更好的事件要使用,或者在应用程序在spring-boot中运行后运行代码的更好方法是什么?

cah*_*hen 251

这很简单:

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

测试版本 1.5.1.RELEASE

  • 有人可能也希望使用`@EventListener(ContextRefreshedEvent.class)`,它在bean创建之后但在服务器启动之前被触发.它可用于在任何请求到达服务器之前执行活动. (10认同)
  • 谢谢.这使我的代码无需任何更改即可运行.再次感谢这么简单的回答.这也适用于@RequestMapping注释,没有任何问题. (6认同)
  • @neeraj,问题是关于在Spring Boot启动后运行代码。如果使用`ContextRefreshedEvent`,它也会在每次刷新后运行。 (2认同)
  • 放置事件侦听器的类是否需要使用组件、服务等进行注释? (2认同)
  • 在Spring Boot 2.0.5.RELEASE上测试 (2认同)
  • 在 2.2.2 版本上测试。它工作得很好。这个解决方案节省了我的时间。 (2认同)
  • 它应该在带有 @Component 的类或带有 Component Type 的类中使用才能正常工作 (2认同)

Ant*_*nov 102

尝试:

@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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于Web服务器部署。 (3认同)
  • 将应用程序作为war文件部署到外部tomcat时,这不起作用.它仅适用于嵌入式tomcat (3认同)

ras*_*orp 88

你试过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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

...

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

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

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

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

刷新后发送ApplicationReadyEvent,并且已处理任何相关的回调以指示应用程序已准备好为请求提供服务.

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

...

  • 作为替代方法,您可以在Bean方法上使用```@EventListener```annotation执行此操作,并将要挂接的类事件作为参数传递. (11认同)
  • 这应该是选择的答案。 (2认同)
  • 在spring-boot 2中,这已经发生了变化。如果您是从1.x移植并使用ApplicationStartedEvent,则现在需要ApplicationStartingEvent。 (2认同)

cjs*_*hno 79

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

@Component
public class Monitor {
    @Autowired private SomeService service

    @PostConstruct
    public void init(){
        // start your monitoring in here
    }
}
Run Code Online (Sandbox Code Playgroud)

init为bean完成任何自动装配之前,不会调用该方法.

  • 有时`@ PostConstruct`会过早发射.例如,当使用Spring Cloud Stream Kafka时,`@ PostConstruct`会在应用程序绑定到Kafka之前触发.Dave Syer的解决方案更好,因为它会及时发射. (13认同)
  • `@ PostConstruct`在初始化期间发生,而不是在之后发生.虽然这在某些情况下很有用,但如果你想在**Spring Boot启动后运行**,那么这不是正确的答案.例如,虽然`@ PostConstruct`没有完成,但没有一个端点可用. (7认同)

Dav*_*yer 60

"Spring Boot"方式是使用a CommandLineRunner.只需添加那种类型的豆子就可以了.在Spring 4.1(Boot 1.2)中,还有SmartInitializingBean一个在所有内容初始化后获得回调.还有SmartLifecycle(从春季开始).

  • 不知道"任意时刻"是什么意思.Spring Boot用户指南和示例提供了使用`CommandLineRunner`(以及更新的`ApplicationRunner`)的示例:http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot -features的命令行浇道. (4认同)
  • 使用`CommandLineRunner的夫妇通常[示例代码](https://gist.github.com/simonovAlexey/51166e11fe80c84f20c19527dd722788) (3认同)

Gim*_*ani 36

您可以使用扩展类ApplicationRunner,重写该run()方法并在其中添加代码.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

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

        //code goes here

    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*own 22

ApplicationReadyEvent实际上只有在您要执行的任务不是正确的服务器操作要求时才有用.启动异步任务以监视某些更改是一个很好的例子.

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

不要试图@PostConstruct用于只应该发生过一次的任务.当你注意到它被多次调用时,你会得到一个粗鲁的惊喜......


fre*_*lys 20

配弹簧配置:

@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");
  }
}
Run Code Online (Sandbox Code Playgroud)


Jef*_*eff 12

SmartInitializingSingleton在spring> 4.1中使用bean

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

}
Run Code Online (Sandbox Code Playgroud)

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


Nar*_*esh 12

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

1. 使用 PostConstruct 注解

@Configuration
public class InitialDataConfiguration {

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

}
Run Code Online (Sandbox Code Playgroud)

2. 使用命令行 runner bean

@Configuration
public class InitialDataConfiguration {

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

  • 我相信`@PostConstruct`方法是bean初始化的一部分。我看到 ApplicationContext 由于“@PostConstruct”方法失败而导致依赖性不满足而无法加载。 (5认同)

小智 10

我真的很喜欢EventListener@cahen ( /sf/answers/3144638171/ )使用注释的建议,因为它非常干净。不幸的是,我无法在 Spring + Kotlin 设置中使用它。对 Kotlin 有用的是将类添加为方法参数:

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


mus*_*ibs 9

您有多种选择:

使用CommandLineRunnerorApplicationRunner作为 Bean 定义:

Spring Boot 在应用程序启动过程快结束时执行这些。在大多数情况下,意志CommandLineRunner可以完成这项工作。以下是使用 Java 8 实现 CommandLineRunner 的示例:

@Bean
public CommandLineRunner commandLineRunner() {
   return (args) -> System.out.println("Hello World");
}
Run Code Online (Sandbox Code Playgroud)

请注意,这args是参数的字符串数组。您还可以提供此接口的实现并将其定义为 Spring 组件:

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Hello World");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您需要更好的参数管理,您可以使用ApplicationRunner。ApplicationRunner 采用ApplicationArguments具有增强参数管理选项的实例。

您还可以使用 Spring 的注释来订购 CommandLineRunner和beans :ApplicationRunner@Order

 @Bean
 @Order(1)
 public CommandLineRunner commandLineRunner() {
    return (args) -> System.out.println("Hello World, Order 1");
 }

 @Bean
 @Order(2)
 public CommandLineRunner commandLineRunner() {
    return (args) -> System.out.println("Hello World, Order 2");
 }
Run Code Online (Sandbox Code Playgroud)

使用Spring Boot的ContextRefreshedEvent:

Spring Boot 在启动时发布多个事件。这些事件指示应用程序启动过程中的一个阶段的完成。您可以监听ContextRefreshedEvent并执行自定义代码:

@EventListener(ContextRefreshedEvent.class)
public void execute() {
    if(alreadyDone) {
      return;
    }
    System.out.println("hello world");
} 
Run Code Online (Sandbox Code Playgroud)

ContextRefreshedEvent已发表多次。因此,请确保检查代码执行是否已完成。


小智 7

Spring boot 提供了一个 ApplicationRunner 接口,其中包含一个在应用程序启动时调用的 run() 方法。但是,我们没有传递给回调方法的原始 String 参数,而是有一个 ApplicationArguments 类的实例。

@Component
public class AppStartupRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //some logic here
    }
}
Run Code Online (Sandbox Code Playgroud)


Pau*_*oso 6

提供一个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));
    }
}
Run Code Online (Sandbox Code Playgroud)


Kal*_*ium 5

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

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent arg0) {
                // EXECUTE YOUR CODE HERE 
    }
}
Run Code Online (Sandbox Code Playgroud)