[java] Spring 시작시 메소드 실행

애플리케이션이 처음 시작될 때 일부 메소드를 실행하는 Spring 3 기능이 있습니까? @Scheduled주석 으로 메소드를 설정하는 트릭을 수행 할 수 있으며 시작 직후 실행되지만 주기적으로 실행됩니다.



답변

“응용 프로그램 시작”이 “응용 프로그램 컨텍스트 시작”을 의미하는 경우 그렇습니다.이 작업을 수행 하는 가장 쉬운 방법여러 가지@PostConstruct있습니다. 다른 옵션을 보려면 링크를 살펴보십시오. 요약하면 다음과 같습니다.

  • 주석이 달린 방법 @PostConstruct
  • afterPropertiesSet()InitializingBean콜백 인터페이스에 의해 정의 된
  • 사용자 정의 구성된 init () 메소드

기술적으로 이들은 컨텍스트 라이프 사이클이 아닌 Bean 라이프 사이클에 연결되지만 99 %의 경우 두 가지가 동일합니다.

컨텍스트 시작 / 종료에 구체적으로 연결해야하는 경우 대신 인터페이스구현할Lifecycle 수 있지만 불필요 할 수 있습니다 .


답변

이것은로 쉽게 수행 할 수 있습니다 ApplicationListener. Spring의 청취를 위해이 작업을 수행했습니다 ContextRefreshedEvent.

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class StartupHousekeeper implements ApplicationListener<ContextRefreshedEvent> {

  @Override
  public void onApplicationEvent(final ContextRefreshedEvent event) {
    // do whatever you need here 
  }
}

애플리케이션 리스너는 Spring에서 동기식으로 실행됩니다. 코드가 한 번만 실행되도록하려면 구성 요소의 상태를 유지하십시오.

최신 정보

Spring 4.2 이상부터는 @EventListener주석을 사용 하여 ContextRefreshedEvent( 이 점을 지적한 @bphilipnyc 덕분에) 관찰 할 수 있습니다 .

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class StartupHousekeeper {

  @EventListener(ContextRefreshedEvent.class)
  public void contextRefreshedEvent() {
    // do whatever you need here 
  }
}


답변

Spring 4.2 이상에서는 이제 간단하게 할 수 있습니다.

@Component
class StartupHousekeeper {

    @EventListener(ContextRefreshedEvent.class)
    public void contextRefreshedEvent() {
        //do whatever
    }
}


답변

스프링 부트를 사용하는 경우 이것이 가장 좋은 대답입니다.

나는 느낌 @PostConstruct등 다양한 수명주기 감탄사가 라운드에 대한 방법입니다합니다. 이로 인해 런타임 문제가 직접 발생하거나 예기치 않은 Bean / 컨텍스트 라이프 사이클 이벤트로 인해 눈에 띄지 않는 결함이 발생할 수 있습니다. 왜 일반 Java를 사용하여 Bean을 직접 호출하지 않습니까? 당신은 여전히 ​​빈을 ‘spring way'(예 : 스프링 AoP 프록시를 통해) 호출합니다 그리고 무엇보다도, 그것은 평범한 자바이며, 그보다 더 간단해질 수는 없습니다. 컨텍스트 리스너 나 홀수 스케줄러가 필요하지 않습니다.

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext app = SpringApplication.run(DemoApplication.class, args);

        MyBean myBean = (MyBean)app.getBean("myBean");

        myBean.invokeMyEntryPoint();
    }
}


답변

@PostConstruct 주석을 참조하려고 할 때 경고가 표시되는 Java 1.8 사용자의 경우, fixedRate 또는 fixedDelay를 사용하여 @Scheduled 작업이 이미있는 경우 수행 할 수있는 @Scheduled 주석을 피기 백하는 대신 종료되었습니다.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@EnableScheduling
@Component
public class ScheduledTasks {

private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class);

private static boolean needToRunStartupMethod = true;

    @Scheduled(fixedRate = 3600000)
    public void keepAlive() {
        //log "alive" every hour for sanity checks
        LOGGER.debug("alive");
        if (needToRunStartupMethod) {
            runOnceOnlyOnStartup();
            needToRunStartupMethod = false;
        }
    }

    public void runOnceOnlyOnStartup() {
        LOGGER.debug("running startup job");
    }

}


답변

우리가 한 일은 org.springframework.web.context.ContextLoaderListener컨텍스트가 시작될 때 무언가를 인쇄하도록 확장 되었습니다.

public class ContextLoaderListener extends org.springframework.web.context.ContextLoaderListener
{
    private static final Logger logger = LoggerFactory.getLogger( ContextLoaderListener.class );

    public ContextLoaderListener()
    {
        logger.info( "Starting application..." );
    }
}

다음에서 서브 클래스를 구성하십시오 web.xml.

<listener>
    <listener-class>
        com.mycomp.myapp.web.context.ContextLoaderListener
    </listener-class>
</listener>


답변

SpringBoot를 사용하면 시작시 @EventListener주석을 통해 메소드를 실행할 수 있습니다

@Component
public class LoadDataOnStartUp
{
    @EventListener(ApplicationReadyEvent.class)
    public void loadData()
    {
        // do something
    }
}