스프링 부트 시작 후 코드 실행


211

스프링 부트 앱이 디렉토리 변경 사항을 모니터링하기 시작한 후에 코드를 실행하고 싶습니다 .

새 스레드를 실행하려고 시도했지만 @Autowired해당 시점에 서비스가 설정되지 않았습니다.

주석을 설정 ApplicationPreparedEvent하기 전에 시작되는를 찾을 수있었습니다 @Autowired. 이상적으로 응용 프로그램이 http 요청을 처리 할 준비가되면 이벤트를 시작하고 싶습니다.

사용하기에 더 좋은 이벤트가 있습니까, 아니면 응용 프로그램이 스프링 부트들어간 후에 더 나은 코드 실행 방법이 있습니까?



스프링 부트는 스프링 부트가 시작된 후 코드를 실행하려고 할 때 사용할 수있는 두 개의 인터페이스 ApplicationRunner 및 CommandLineRunner를 제공합니다. 구현 예 -jhooq.com/applicationrunner-spring-boot
Rahul Wagh

답변:


121

시험:

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

6
외부 Tomcat에 응용 프로그램을 war 파일로 배포 할 때는 작동하지 않습니다. 임베디드 바람둥이에서만 작동
Saurabh

아니요, 작동하지 않습니다. 그러나이 사용 사례에서는 대신에보다 명시적인 방법을 선호 @Component합니다. war 파일에서 작동하게하려면 @cjstehno의 답변을 참조하십시오.
Anton Bessonov 2016 년

320

다음과 같이 간단합니다.

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

버전에서 테스트 1.5.1.RELEASE


7
감사합니다. 이것은 내 코드가 아무런 변경없이 작동하게했습니다. 그런 간단한 답변에 다시 한번 감사드립니다. 이것은 문제없이 @RequestMapping 주석과 함께 작동합니다.
Harshit

16
누군가가 @EventListener(ContextRefreshedEvent.class)대신 사용하기 를 원할 수도 있습니다. 빈 생성 후, 서버가 시작되기 전에 트리거됩니다. 요청이 서버에 도달하기 전에 활동을 수행하는 데 사용할 수 있습니다.
neeraj

3
@neeraj, 문제는 Spring Boot가 시작된 후 코드를 실행하는 것에 관한 것입니다. 를 사용하면 ContextRefreshedEvent모든 새로 고침 후에도 실행됩니다.
cahen

4
봄 부팅 2.0.5.RELEASE 테스트
ritesh

2
2.2.2 릴리스에서 테스트되었습니다. 완벽하게 작동합니다. 이 솔루션은 시간을 절약 해줍니다.
Arphile

96

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는 컨텍스트에서 사용될 환경이 알려져있을 때, 그러나 컨텍스트가 작성되기 전에 전송됩니다.

ApplicationPreparedEvent는 새로 고침이 시작되기 직전이지만 Bean 정의가로드 된 후에 전송됩니다.

새로 고친 후 ApplicationReadyEvent가 전송되고 관련 콜백이 처리되어 응용 프로그램이 요청을 처리 할 준비가되었음을 나타냅니다.

시작할 때 예외가 있으면 ApplicationFailedEvent가 전송됩니다.

...


11
또는 @EventListenerBean 메소드에 주석을 사용하여 연결하려는 클래스 이벤트를 인수로 전달 하여이를 수행 할 수 있습니다 .
padilo

2
이것이 정답입니다.
varun113

2
이것은 spring-boot 2에서 변경되었습니다. 1.x에서 포팅하고 ApplicationStartedEvent를 사용하고 있다면 ApplicationStartingEvent가 대신 필요합니다.
앤디 브라운

이것은 절대적으로 잘 작동하며 최선의 방법이라고 생각합니다.
AVINASH SHRIMALI

당신은 최고입니다
ancm

83

초기화시 모니터를 시작하는 Bean을 작성하지 마십시오.

@Component
public class Monitor {
    @Autowired private SomeService service

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

init어떤에서 autowiring이 콩에 대한 완료 될 때까지 메서드가 호출되지 않습니다.


14
때때로 @PostConstruct너무 일찍 발생합니다. 예를 들어 Spring Cloud Stream Kafka를 사용하는 경우 @PostConstruct애플리케이션이 Kafka에 바인딩되기 전에 시작됩니다. Dave Syer의 솔루션은시기 적절하게 실행되므로 더 좋습니다.
Elnur Abdurrakhimov

9
@PostConstruct초기화가 아닌 이후에 발생합니다. 이것은 어떤 경우에는 유용 ​​할 수 있지만 Spring Boot가 시작된 후에 실행하려는 경우 정답이 아닙니다 . 예를 들어, @PostConstruct완료되지는 않지만 사용 가능한 엔드 포인트가 없습니다.
cahen

63

"Spring Boot"방법은을 사용하는 것 CommandLineRunner입니다. 해당 유형의 콩을 추가하면 좋습니다. Spring 4.1 (Boot 1.2)에는 SmartInitializingBean모든 것이 초기화 된 후 콜백이 발생합니다. 그리고 SmartLifecycle(봄 3부터) 있습니다.


그 예가 있습니까? 앱이 실행 된 후 임의의 순간에 명령 행을 통해 Bean을 실행할 수 있습니까?
Emilio

5
"임의의 순간"의 의미를 모릅니다. 봄 부팅 사용자 가이드 및 샘플은 사용 예가 CommandLineRunner(그리고 새로운 ApplicationRunner:) docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/...를 .
Dave Syer

라이프 사이클은 응용 프로그램의 시작 / 중지 단계에서 비동기 작업을 수행하는 데 선호되는 옵션이며 CommandLineRunner와 InitializingBeans 사이의 다른 차이점을 찾으려고 노력하고 있지만 그에 대해서는 아무것도 찾을 수 없습니다.
saljuama

3
일반적인 예제 코드 사용CommandLineRunner
Alexey Simonov

41

를 사용하여 클래스를 확장 ApplicationRunner하고 run()메서드를 재정의 하고 코드를 추가 할 수 있습니다.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

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

        //code goes here

    }
}

스프링 부트에 완벽합니다. 그러나 클래스에 ApplicationScope가있을 때 run () 메소드가 두 번 호출되었습니다. 따라서 위의 PostConstruct 메소드가 더 잘 작동했습니다.
Sam

26

ApplicationReadyEvent수행하려는 작업이 올바른 서버 작업에 필요하지 않은 경우에만 유용합니다. 변경 사항을 모니터링하기 위해 비동기 작업을 시작하는 것이 좋은 예입니다.

그러나 작업이 완료 될 때까지 서버가 '준비되지 않음'상태 인 경우 REST 포트가 열리고 서버가 비즈니스 용으로 열리기 전에SmartInitializingSingleton 콜백을 받기 때문에 구현하는 것이 좋습니다 .

@PostConstruct한 번만 발생해야하는 작업 에 사용하려는 유혹을받지 마십시오 . 여러 번 호출되는 것을 발견하면 무례한 놀라움을 느낄 것입니다 ...


이것이 정답입니다. @Andy가 지적했듯이 SmartInitializingSingleton은 포트가 열리기 직전에 호출됩니다.
Srikanth

24

스프링 구성으로 :

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

12

SmartInitializingSingleton봄에 콩을 사용하십시오 > 4.1

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

}

대안으로 CommandLineRunnerBean을 구현하거나로 Bean 메소드에 주석을 달 수 있습니다 @PostConstruct.


해당 메소드 내에서 자동 유선 종속성이 필요할 수 있습니까? 프로필을 설정하고 싶습니다
LppEdd

7

매력처럼 작동하는 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));
    }
}

7

이것을 시도하면 응용 프로그램 컨텍스트가 완전히 시작되면 코드가 실행됩니다.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

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

6

EventListener@cahen ( https://stackoverflow.com/a/44923402/9122660 ) 의 주석 사용 제안 은 매우 깨끗하기 때문에 정말 좋습니다. 불행히도 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") } }
Ahmed na

@SpringBootApplication 클래스에는 필요하지 않습니다. 모든 구성 클래스는
George Marin

5

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

3

스프링 부트 응용 프로그램을 위해 CommandLineRunner를 구현하십시오. run 메소드를 구현해야합니다.

public classs SpringBootApplication implements CommandLineRunner{

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

        }
}

0

CommandLineRunner 또는 ApplicationRunner를 사용하는 최상의 방법 유일한 차이점은 run () 메소드입니다. CommandLineRunner는 문자열 배열을 허용하고 ApplicationRunner는 ApplicationArugument를 허용합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.