简体   繁体   English

Spring Boot 启动后运行代码

[英]Running code after Spring Boot starts

I want to run code after my spring-boot app starts to monitor a directory for changes.我想在我的spring-boot应用程序开始监视目录更改后运行代码。

I have tried running a new thread but the @Autowired services have not been set at that point.我曾尝试运行一个新线程,但此时尚未设置@Autowired服务。

I have been able to find ApplicationPreparedEvent , which fires before the @Autowired annotations are set.我已经能够找到ApplicationPreparedEvent ,它在设置@Autowired注释之前触发。 Ideally I would like the event to fire once the application is ready to process http requests.理想情况下,我希望在应用程序准备好处理 http 请求后触发该事件。

Is there a better event to use, or a better way of running code after the application is live in spring-boot ?应用程序在spring-boot中上线后,是否有更好的事件可供使用或运行代码的更好方法?

It is as simple as this:就这么简单:

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

Tested on version 1.5.1.RELEASE1.5.1.RELEASE版本上1.5.1.RELEASE

Try:尝试:

@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
    }
}

Have you tried ApplicationReadyEvent?您是否尝试过 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;
  }
}

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

This is what the documentation mentions about the startup events:这是文档中提到的有关启动事件的内容:

... ...

Application events are sent in the following order, as your application runs:在应用程序运行时,应用程序事件按以下顺序发送:

An ApplicationStartedEvent is sent at the start of a run, but before any processing except the registration of listeners and initializers. ApplicationStartedEvent 在运行开始时发送,但在除注册侦听器和初始化程序之外的任何处理之前发送。

An ApplicationEnvironmentPreparedEvent is sent when the Environment to be used in the context is known, but before the context is created.当要在上下文中使用的环境已知时,但在创建上下文之前,将发送 ApplicationEnvironmentPreparedEvent。

An ApplicationPreparedEvent is sent just before the refresh is started, but after bean definitions have been loaded. ApplicationPreparedEvent 在刷新开始之前发送,但在 bean 定义加载之后。

An ApplicationReadyEvent is sent after the refresh and any related callbacks have been processed to indicate the application is ready to service requests.刷新后发送 ApplicationReadyEvent 并且处理任何相关的回调以指示应用程序已准备好为请求提供服务。

An ApplicationFailedEvent is sent if there is an exception on startup.如果启动时出现异常,则发送 ApplicationFailedEvent。

... ...

Why not just create a bean that starts your monitor on initialization, something like:为什么不创建一个在初始化时启动监视器的 bean,例如:

@Component
public class Monitor {
    @Autowired private SomeService service

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

the init method will not be called until any autowiring is done for the bean.在为 bean 完成任何自动装配之前,不会调用init方法。

The "Spring Boot" way is to use a CommandLineRunner . “Spring Boot”方式是使用CommandLineRunner Just add beans of that type and you are good to go.只需添加那种类型的豆子,你就可以开始了。 In Spring 4.1 (Boot 1.2) there is also a SmartInitializingBean which gets a callback after everything has initialized.在 Spring 4.1 (Boot 1.2) 中还有一个SmartInitializingBean ,它在一切都初始化后得到一个回调。 And there is SmartLifecycle (from Spring 3).还有SmartLifecycle (来自 Spring 3)。

You can extend a class using ApplicationRunner , override the run() method and add the code there.您可以使用ApplicationRunner扩展一个类,覆盖run()方法并在那里添加代码。

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

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

        //code goes here

    }
}

ApplicationReadyEvent is really only useful if the task you want to perform is not a requirement for correct server operation. ApplicationReadyEvent只有在您要执行的任务不是正确服务器操作的必要条件时才有用。 Starting an async task to monitor something for changes is a good example.启动异步任务来监视某些更改是一个很好的例子。

If, however your server is in a 'not ready' state until the task is completed then it's better to implement SmartInitializingSingleton because you'll get the callback before your REST port has been opened and your server is open for business.但是,如果您的服务器在任务完成之前处于“未准备好”状态,那么最好实施SmartInitializingSingleton因为您将REST 端口打开并且您的服务器开放业务之前收到回调。

Don't be tempted to use @PostConstruct for tasks that should only happen once ever.不要试图将@PostConstruct用于应该只发生一次的任务。 You'll get a rude surprise when you notice it being called multiple times...当你注意到它被多次调用时,你会得到一个粗鲁的惊喜......

With spring configuration :弹簧配置:

@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");
  }
}

Use a SmartInitializingSingleton bean in spring > 4.1在 spring > 4.1 中使用SmartInitializingSingleton bean

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

}

As alternative a CommandLineRunner bean can be implemented or annotating a bean method with @PostConstruct .作为替代,可以实现CommandLineRunner bean 或使用@PostConstruct注释 bean 方法。

Best way to execute block of code after Spring Boot application started is using PostConstruct annotation.Or also you can use command line runner for the same.在 Spring Boot 应用程序启动后执行代码块的最佳方法是使用 PostConstruct 注释。或者您也可以使用命令行运行程序。

1. Using PostConstruct annotation 1. 使用 PostConstruct 注解

@Configuration
public class InitialDataConfiguration {

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

}

2. Using command line runner bean 2. 使用命令行 runner bean

@Configuration
public class InitialDataConfiguration {

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

I really like the suggestion for usage of the EventListener annotation by @cahen ( https://stackoverflow.com/a/44923402/9122660 ) since it is very clean.我真的很喜欢 @cahen ( https://stackoverflow.com/a/44923402/9122660 ) 使用EventListener注释的建议,因为它非常干净。 Unfortunately I could not get this to work in a Spring + Kotlin setup.不幸的是,我无法在 Spring + Kotlin 设置中使用它。 What does work for Kotlin is adding the class as a method parameter:对 Kotlin 有用的是将类添加为方法参数:

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

Providing an example for Dave Syer answer, which worked like a charm:为 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));
    }
}

Try this one and it will run your code when the application context has fully started.试试这个,它会在应用程序上下文完全启动时运行你的代码。

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

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

just implement CommandLineRunner for spring boot application.只需为 Spring Boot 应用程序实现 CommandLineRunner 即可。 You need to implement run method,你需要实现run方法,

public classs SpringBootApplication implements CommandLineRunner{

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

        }
}

Spring boot provides an ApplicationRunner interface with a run() method to be invoked at application startup. Spring boot 提供了一个 ApplicationRunner 接口,其中包含一个在应用程序启动时调用的 run() 方法。 However, instead of raw String arguments passed to the callback method, we have an instance of the ApplicationArguments class.但是,我们有一个 ApplicationArguments 类的实例,而不是传递给回调方法的原始字符串参数。

@Component
public class AppStartupRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //some logic here
    }
}

you can use @Component你可以使用@Component

@RequiredArgsConstructor
@Component
@Slf4j
public class BeerLoader implements CommandLineRunner {
    //declare 

    @Override
    public void run(String... args) throws Exception {
        //some code here 

    }

You have several choices:您有多种选择:

Using CommandLineRunner or ApplicationRunner as a Bean definition:使用CommandLineRunnerApplicationRunner作为 Bean 定义:

Spring Boot executes these towards the end of the application startup process. Spring Boot 在应用程序启动过程结束时执行这些。 In most circumstances, the CommandLineRunner will do the job.在大多数情况下, CommandLineRunner将完成这项工作。 Following is an example of a CommandLineRunner implementation with Java 8:以下是 Java 8 的 CommandLineRunner 实现示例:

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

Note that the args is the String array of arguments.请注意, argsargs的 String 数组。 You can also provide an implementation of this interface and define it as a Spring Component:您还可以提供此接口的实现并将其定义为 Spring 组件:

@Component
public class MyCommandLineRunner implements CommandLineRunner {

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

You can use the ApplicationRunner if you need better argument management.如果您需要更好的参数管理,您可以使用ApplicationRunner ApplicationRunner takes an ApplicationArguments instance that has enhanced argument management options. ApplicationRunner 采用具有增强的参数管理选项的ApplicationArguments实例。

You can also order the CommandLineRunner and ApplicationRunner beans using Spring's @Order annotation:您还可以使用 Spring 的@Order注释对CommandLineRunnerApplicationRunner bean 进行排序:

 @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");
 }

Using Spring Boot's ContextRefreshedEvent:使用 Spring Boot 的 ContextRefreshedEvent:

Spring Boot publishes several events at startup. Spring Boot 在启动时发布几个事件。 These events indicate the completion of a phase in the application startup process.这些事件表明应用程序启动过程中的一个阶段已完成。 You can listen to the ContextRefreshedEvent and execute custom code:您可以监听ContextRefreshedEvent并执行自定义代码:

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

ContextRefreshedEvent is published several times. ContextRefreshedEvent被发布多次。 Thus, ensure to put a check whether the code execution is already finished.因此,确保检查代码执行是否已经完成。

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

If you mean running peace of code once after the application started, you can use the CommandLineRunner as below:如果你的意思是在应用程序启动后运行一次和平代码,你可以使用 CommandLineRunner 如下:

@SpringBootApplication
public class SpringBootApplication 
  implements CommandLineRunner {

private static Logger LOG = LoggerFactory
  .getLogger(SpringBootConsoleApplication.class);

public static void main(String[] args) {
    LOG.info("STARTING THE APPLICATION");
    SpringApplication.run(SpringBootConsoleApplication.class, args);
    LOG.info("APPLICATION FINISHED");
}

@Override
public void run(String... args) {
    // enter code you want to run after app loaded here
    LOG.info("EXECUTING : command line runner");

    for (int i = 0; i < args.length; ++i) {
        LOG.info("args[{}]: {}", i, args[i]);
    }
}

} }

Otherwise, you can use the DevTools dependency, which help you to run new codes without manually restarting the application.否则,您可以使用 DevTools 依赖项,它可以帮助您运行新代码而无需手动重新启动应用程序。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

don't forget to add these codes to your pom.xml to avoid version warnings:不要忘记将这些代码添加到您的 pom.xml 以避免版本警告:

   <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
    </properties>

 <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>

give it a thump up if this was helpful to you!如果对您有帮助,请点个赞!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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