在Spring Boot启动后运行代码

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

我已经尝试运行一个新线程,但@Autowired服务尚未设置在这一点上。

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

是否有更好的事件可以使用,或者在应用程序在spring-boot中激活后运行代码的更好方式?

395302 次浏览

试一试:

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

为什么不创建一个bean,在初始化时启动监视器呢?

@Component
public class Monitor {
@Autowired private SomeService service


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

init方法将不会被调用,直到bean的任何自动装配完成。

“Spring Boot”的方法是使用CommandLineRunner。只需添加该类型的bean,就可以了。在Spring 4.1 (Boot 1.2)中,还有一个SmartInitializingBean,它在所有东西初始化后得到一个回调。还有SmartLifecycle(来自Spring 3)。

你试过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 创建. < / p >

ApplicationPreparedEvent在启动刷新之前,但在加载bean定义之后发送。

一个ApplicationReadyEvent在刷新后发送,任何相关的回调已经被处理,以表明应用程序已经准备好 服务请求。< / p >

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

...

你可以使用ApplicationRunner扩展一个类,覆盖run()方法并在那里添加代码。

import org.springframework.boot.ApplicationRunner;


@Component
public class ServerInitializer implements ApplicationRunner {


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


//code goes here


}
}

为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));
}
}

在spring > 4.1中使用SmartInitializingSingleton bean

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


}

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

其实很简单:

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

1.5.1.RELEASE版本上测试

ApplicationReadyEvent只在你想要执行的任务不是正确服务器操作的必要条件时才有用。启动异步任务来监视某些内容的更改就是一个很好的例子。

然而,如果你的服务器在任务完成之前处于“未准备好”状态,那么最好实现SmartInitializingSingleton,因为你会得到回调之前,你的REST端口已经打开,你的服务器是开放的业务。

不要试图将@PostConstruct用于只应该发生一次的任务。当你注意到它被多次调用时,你会感到粗鲁的惊讶……

为spring boot应用程序实现CommandLineRunner。 你需要实现run方法,

public classs SpringBootApplication implements CommandLineRunner{


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


}
}

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

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {


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

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

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

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

CommandLineRunner或ApplicationRunner的最佳方式 两者之间唯一的区别是run()方法

. CommandLineRunner接受字符串数组,ApplicationRunner接受ApplicationArugument

你可以使用@Component

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


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


}

你有几个选择:

使用CommandLineRunnerApplicationRunner作为Bean定义:

Spring Boot在应用程序启动过程的末尾执行这些命令。在大多数情况下,CommandLineRunner将完成这项工作。下面是一个用Java 8实现CommandLineRunner的例子:

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

注意args是参数的String数组。你也可以提供这个接口的实现,并将其定义为Spring组件:

@Component
public class MyCommandLineRunner implements CommandLineRunner {


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

如果需要更好的参数管理,可以使用ApplicationRunner。ApplicationRunner接受一个ApplicationArguments实例,该实例具有增强的参数管理选项。

你也可以使用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");
}

使用Spring Boot的ContextRefreshedEvent:

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

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

ContextRefreshedEvent被发布了几次。因此,确保检查代码执行是否已经完成。

Spring引导提供了一个带有run()方法的ApplicationRunner接口,在应用程序启动时调用该方法。 但是,我们没有将原始的String参数传递给回调方法,而是使用了ApplicationArguments类的实例
@Component
public class AppStartupRunner implements ApplicationRunner {


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

如果你的意思是在应用程序启动后运行一次peace of code,你可以如下所示使用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]);
}
}

否则,您可以使用DevTools依赖项,它可以帮助您在不手动重新启动应用程序的情况下运行新代码。

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

不要忘记将这些代码添加到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>

如果这对你有帮助,给它一个重击!