我想在我的 spring-boot 应用程序开始监视目录的更改后运行代码。
我已尝试运行一个新线程,但此时尚未设置 @Autowired
服务。
我已经能够找到 ApplicationPreparedEvent
,它在设置 @Autowired
注释之前触发。理想情况下,我希望在应用程序准备好处理 http 请求后触发事件。
在应用程序在 spring-boot 中运行之后,是否有更好的事件可以使用,或者运行代码的更好方式?
就这么简单:
@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
System.out.println("hello world, I have just started up");
}
在版本 1.5.1.RELEASE
上测试
尝试:
@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
}
}
@Component
。请参阅@cjstehno 的答案以使其在战争文件中工作。
你试过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/
这是 documentation 提到的有关启动事件的内容:
... 应用程序事件在您的应用程序运行时按以下顺序发送: ApplicationStartedEvent 在运行开始时发送,但在除侦听器和初始化程序的注册之外的任何处理之前发送。 ApplicationEnvironmentPreparedEvent 在上下文中使用的环境已知时发送,但在创建上下文之前。 ApplicationPreparedEvent 在刷新开始之前发送,但在加载 bean 定义之后。刷新后发送 ApplicationReadyEvent 并处理任何相关的回调以指示应用程序已准备好为请求提供服务。如果启动时出现异常,则会发送 ApplicationFailedEvent。 ...
@EventListener
注解,将要挂钩的类事件作为参数传递。
为什么不创建一个在初始化时启动监视器的 bean,例如:
@Component
public class Monitor {
@Autowired private SomeService service
@PostConstruct
public void init(){
// start your monitoring in here
}
}
在对 bean 进行任何自动装配之前,不会调用 init
方法。
@PostConstruct
触发得太早。例如,当使用 Spring Cloud Stream Kafka 时,@PostConstruct
在应用程序绑定到 Kafka 之前触发。 Dave Syer 的解决方案更好,因为它可以及时触发。
@PostConstruct
发生在初始化期间,而不是之后。虽然这在某些情况下很有用,但如果您想在 Spring Boot 启动后运行,这不是正确的答案。例如,虽然 @PostConstruct
没有完成,但没有一个端点可用。
@PostConstruct
中执行任何长时间运行的操作(例如带有重试回退的 HTTP 请求),您将不会获得良好的行为,因为发送 SIGTERM 不会中断运行 @PostConstruct
的线程,因此您的应用程序拒绝关闭直到该方法退出。
“Spring Boot”方式是使用 CommandLineRunner
。只需添加那种类型的豆子,你就可以走了。在 Spring 4.1 (Boot 1.2) 中还有一个 SmartInitializingBean
,它在所有内容初始化后都会获得回调。还有 SmartLifecycle
(来自 Spring 3)。
CommandLineRunner
(和较新的 ApplicationRunner
)的示例:docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/…。
CommandLineRunner
的几个常用 example code
@EventListener(ApplicationReadyEvent.class)
更好?
您可以使用 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
只有在您要执行的任务不是正确服务器操作的要求时才真正有用。启动一个异步任务来监控某些东西的变化就是一个很好的例子。
但是,如果您的服务器在任务完成之前处于“未就绪”状态,那么最好实施 SmartInitializingSingleton
,因为您将在您的 REST 端口打开和您的服务器之前获得回调营业。
不要试图将 @PostConstruct
用于应该只发生一次的任务。当您注意到它被多次调用时,您会感到非常惊讶......
在 spring 中使用 SmartInitializingSingleton
bean > 4.1
@Bean
public SmartInitializingSingleton importProcessor() {
return () -> {
doStuff();
};
}
作为替代方案,可以实现 CommandLineRunner
bean 或使用 @PostConstruct
注释 bean 方法。
在 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...");
};
}
}
@PostConstruct
方法是 bean 初始化的一部分。我已经看到由于 @PostConstruct
方法失败导致依赖不满足而导致 ApplicationContext 无法加载。
为 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));
}
}
我真的很喜欢@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");
}
@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
边
你有几个选择:
使用 CommandLineRunner
或 ApplicationRunner
作为 Bean 定义:
Spring Boot 在应用程序启动过程结束时执行这些。在大多数情况下,CommandLineRunner
将完成这项工作。以下是使用 Java 8 实现 CommandLineRunner 的示例:
@Bean
public CommandLineRunner commandLineRunner() {
return (args) -> System.out.println("Hello World");
}
请注意,args
是参数的字符串数组。您还可以提供此接口的实现并将其定义为 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
注释订购 CommandLineRunner
和 ApplicationRunner
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
多次发布。因此,请确保检查代码执行是否已经完成。
试试这个,它会在应用程序上下文完全启动时运行你的代码。
@Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent arg0) {
// EXECUTE YOUR CODE HERE
}
}
ContextRefreshedEvent
can be triggered multiple times
只需为 Spring Boot 应用程序实现 CommandLineRunner。您需要实现运行方法,
public classs SpringBootApplication implements CommandLineRunner{
@Override
public void run(String... arg0) throws Exception {
// write your logic here
}
}
你可以使用@Component
@RequiredArgsConstructor
@Component
@Slf4j
public class BeerLoader implements CommandLineRunner {
//declare
@Override
public void run(String... args) throws Exception {
//some code here
}
使用 CommandLineRunner 或 ApplicationRunner 的最佳方式 唯一的区别是 run() 方法 CommandLineRunner 接受字符串数组,而 ApplicationRunner 接受 ApplicationArugument。
Spring boot 提供了一个 ApplicationRunner 接口,该接口带有一个在应用程序启动时调用的 run() 方法。但是,我们有一个 ApplicationArguments 类的实例,而不是传递给回调方法的原始字符串参数。
@Component
public class AppStartupRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
//some logic here
}
}
不定期副业成功案例分享
@EventListener(ContextRefreshedEvent.class)
,它会在 bean 创建之后但在服务器启动之前触发。它可用于在任何请求到达服务器之前执行活动。