ChatGPT解决这个技术问题 Extra ChatGPT

Spring Boot 启动后运行代码

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

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

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

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

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

c
cahen

就这么简单:

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

在版本 1.5.1.RELEASE 上测试


感谢您。这使我的代码无需任何更改即可工作。再次感谢您提供如此简单的答案。这也适用于 @RequestMapping 注释,没有任何问题。
有人可能还希望改用 @EventListener(ContextRefreshedEvent.class),它会在 bean 创建之后但在服务器启动之前触发。它可用于在任何请求到达服务器之前执行活动。
放置事件监听器的这个类是否需要用组件、服务等进行注释?
在 Spring Boot 2.0.5.RELEASE 上测试
在 2.2.2 版本上测试。它完美地工作。这个解决方案节省了我的时间。
A
Anton Bessonov

尝试:

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

当您将应用程序作为 war 文件部署到外部 tomcat 时,这不起作用。它仅适用于嵌入式 tomcat
不,它不起作用。但在这个用例中,我喜欢更明确的方式而不是 @Component。请参阅@cjstehno 的答案以使其在战争文件中工作。
C
Community

你试过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。 ...


作为替代方案,您可以在 Bean 方法上使用@EventListener注解,将要挂钩的类事件作为参数传递。
这在 spring-boot 2 中发生了变化。如果您从 1.x 移植并使用 ApplicationStartedEvent,那么您现在需要 ApplicationStartingEvent。
c
cjstehno

为什么不创建一个在初始化时启动监视器的 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 没有完成,但没有一个端点可用。
不完全按照 OP 问题。在@PostConstruct,这个bean被构造,就像这个类范围内的bean是自动装配的,等等,但是整个应用程序可能还没有准备好,例如,其他bean可能仍在注入或装配过程中。
如果您在 @PostConstruct 中执行任何长时间运行的操作(例如带有重试回退的 HTTP 请求),您将不会获得良好的行为,因为发送 SIGTERM 不会中断运行 @PostConstruct 的线程,因此您的应用程序拒绝关闭直到该方法退出。
D
Dave Syer

“Spring Boot”方式是使用 CommandLineRunner。只需添加那种类型的豆子,你就可以走了。在 Spring 4.1 (Boot 1.2) 中还有一个 SmartInitializingBean ,它在所有内容初始化后都会获得回调。还有 SmartLifecycle(来自 Spring 3)。


有什么例子吗?是否可以在应用程序运行后通过命令行在任意时刻执行 bean?
不知道你所说的“任意时刻”是什么意思。 Spring Boot 用户指南和示例提供了使用 CommandLineRunner(和较新的 ApplicationRunner)的示例:docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/…
我发现,Lifecycle 是在应用程序的启动/停止阶段执行异步任务的首选选项,我试图发现 CommandLineRunner 和 InitializingBeans 之间的其他差异,但找不到任何相关信息。
使用 CommandLineRunner 的几个常用 example code
如果您不需要访问命令行参数,为什么它比 @EventListener(ApplicationReadyEvent.class) 更好?
G
Gimhani

您可以使用 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 方法效果更好。
A
Andy Brown

ApplicationReadyEvent 只有在您要执行的任务不是正确服务器操作的要求时才真正有用。启动一个异步任务来监控某些东西的变化就是一个很好的例子。

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

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


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

在 spring 中使用 SmartInitializingSingleton bean > 4.1

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

}

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


我可以在该方法中要求 Autowired 依赖项吗?我想设置个人资料
N
Naresh Bhadke

在 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 无法加载。
P
Paulo Pedroso

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

O
Ostecke

我真的很喜欢@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应用程序类中,不要随意放在@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
你不需要把它放在@SpringBootApplication 类中。任何配置类都可以
S
Somnath Musib

你有几个选择:

使用 CommandLineRunnerApplicationRunner 作为 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 注释订购 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 多次发布。因此,请确保检查代码执行是否已经完成。


K
Kalifornium

试试这个,它会在应用程序上下文完全启动时运行你的代码。

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

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

请注意,ContextRefreshedEvent can be triggered multiple times
p
prasad kp

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

public classs SpringBootApplication implements CommandLineRunner{

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

        }
}

B
BRAIEK AYEMN

你可以使用@Component

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

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

    }

R
Rushi Vanga

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


V
Veeresh Devireddy

Spring boot 提供了一个 ApplicationRunner 接口,该接口带有一个在应用程序启动时调用的 run() 方法。但是,我们有一个 ApplicationArguments 类的实例,而不是传递给回调方法的原始字符串参数。

@Component
    public class AppStartupRunner implements ApplicationRunner {

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