1.6.1 라이프 사이클 콜백

컨테이너의 빈 라이프 사이클 관리와 상호 작용하려면 Spring InitializingBeanDisposableBean인터페이스를 구현할 수 있습니다 . 컨테이너 는 bean을 초기화하고 파기 할 때 bean이 특정 조치를 수행하도록 전자에 afterPropertiesSet()와 후자destroy()를 호출 합니다 .

스프링은 빈 을 관리하는 컨테이너이다. 따라서 빈 객체를 생성하고, 초기화및 소멸 등 일련의 과정들을 담당하게 된다. 즉 스프링 컨테이너에 저장되는 빈 객체는 생성, 초기화, 소멸의 라이프 사이클을 가지게 된다.

스프링 컨테이너가 초기화 될 때, 스프링 컨테이너는 가장 먼저 빈 객체를 생성하고, <property> <constructor-arg> 태그로 지정한 의존을 설정한다. 이 때 자동 주입을 통한 의존 설정도 수행된다. 모든 의존 설정이 완료되면, 스프링은 빈 객체가 지정한 메소드를 호출해서 빈 객체의 초기화를 수행한다.

그리고 스프링 컨테이너를 종료하면, 스프링 컨테이너는 빈 객체가 지정한 메소드를 호출해서 빈 객체의 소멸을 처리한다. 빈 객체를 초기화하고 소멸하기 위한 메소드를 사용하기 위해서, 빈 객체는 스프링의 InitializingBean, DisposableBean 인터페이스를 구현해야 한다.

초기화 과정이 필요한 빈 객체는 InitializingBean 인터페이스를 구현해서 afterPropertiesSet( ) 메소드를 적절히 작성하면 되고, 소멸 과정이 필요한 빈 객체는 DisposableBean 인터페이스를 구현해서 destroy( ) 메소드를 적절히 작성하면 되는 것이다.

데이터베이스 커넥션 풀을 위한 빈 객체가 있다면 초기화 과정에서 데이터베이스와 연결을 생성하고,소멸 과정에서 데이터베이스와 연결을 끊어주면 된다

JSR-250 @PostConstruct@PreDestroy주석은 일반적으로 현대 스프링 애플리케이션에서 라이프 사이클 콜백을 받는 가장 좋은 방법으로 간주됩니다. 이러한 주석을 사용하면 빈이 Spring 고유의 인터페이스에 결합되지 않는다는 것을 의미한다. 자세한 내용은 참조 @PostConstruct 와 @PreDestroy사용 .

JSR-250 주석을 사용하고 싶지 않지만 여전히 결합을 제거하고싶다면 객체 init-methoddestroy-method객체 정의 메타 데이터를 사용하는 것이 좋습니다.

@PostConstruct어노테이션과 @PreDestroy어노테이션은 라이클 초기화 및 제거과정을 제공한다. @PostConstruct 어노테이션은 의존하는 객체를 설정한 이후에 초기화 작업을 수행 할 메서드에 적용되며(초기화될 때 메소드가 실행), @PreDestroy 어노테이션은 컨테이너에게 객체를 제거하기 전에 호출 될 메서드에 적용된다. 즉, 스프링 설정 파일에서 init-method 속성과 destroy-mehtod속성을 이용하여 명시한 메서드와 동일한 시점에 실행 된다.

내부적으로 Spring Framework는 BeanPostProcessor구현을 사용 하여, 적절한 메소드를 찾아 호출 할 수있는 모든 콜백 인터페이스를 처리합니다. 사용자 정의 기능이나 다른 라이프 사이클 동작이 필요한 경우 Spring은 기본적으로 제공하지 않으므로 BeanPostProcessor직접 구현할 수 있습니다 . 자세한 내용은 컨테이너 확장 지점을 참조하십시오 .

빈(Bean)의 설정을 후처리(postprocessing)함으로써 빈의 생명 주기와 빈 팩토리의 생명주기에 관여. - 빈의 초기화 되기 전, 초기화 된 후 2개의 기회를 제공. - 빈 프로퍼티의 유효성 검사 등에 사용. - 다른 초기화 메소드인 afterPropertiesSet()과 init-method가 호출되기 직전과 직후에 호출되어짐.

public interface BeanPostProcessor {

Object postProcessBeforeInitialization(Object bean, String name) throws BeansException;

Object postProcessAfterInitialization(Object bean, String name) trhows BeansException; ...

Spring 관리 객체는 초기화 및 폐기 콜백 외에도 Lifecycle인터페이스를 구현하여 해당 객체가 컨테이너의 자체 수명주기에 따라 시작 및 종료 프로세스에 참여할 수 있도록합니다.

라이프 사이클 콜백 인터페이스는이 섹션에서 설명합니다.

초기화 콜백

org.springframework.beans.factory.InitializingBean인터페이스는 컨테이너가 빈에 필요한 모든 속성을 설정 한 후 빈 초기화 작업을 수행 할 수 있습니다. InitializingBean인터페이스는 단일 메소드를 지정합니다.

void afterPropertiesSet() throws Exception;

InitializingBeanSpring에 코드를 불필요하게 연결하기 때문에 인터페이스를 사용하지 않는 것이 좋습니다 . 다른방법으로 @PostConstruct주석을 사용하거나 POJO 초기화 메소드를 지정하는 것이 좋습니다 . XML 기반 구성 메타 데이터의 경우 init-method특성을 사용하여 인수가없는 무효 서명이있는 메서드의 이름을 지정할 수 있습니다 .

: you can use the init-method attribute to specify the name of the method that has a void no-argument signature.

Java 구성을 사용하면 @Bean의 initMethod 속성을 사용할 수 있습니다. 라이프 사이클 콜백 수신을 참조하십시오. 다음 예제를 고려하십시오.

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {

    public void init() {
        // do some initialization work
    }
}

앞의 예제는 다음 예제 (두 개의 목록으로 구성)와 거의 동일한 효과를냅니다.

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean {

    public void afterPropertiesSet() {
        // do some initialization work
    }
}

그러나 앞의 두 예제 중 첫 번째 예제는 코드를 Spring에 연결하지 않습니다. : 스프링에 안쓴다는 것 같음 : 그럼 왜 말해주지 : 쳐봐도 예제가 안나오긴 함

파괴 콜백

org.springframework.beans.factory.DisposableBean인터페이스를 구현하면 컨테이너가 포함 된 컨테이너가 콜백 될 때 콜백을받을 수 있습니다. DisposableBean인터페이스는 단일 메소드를 지정한다.

void destroy() throws Exception;

DisposableBean콜백 인터페이스는 불필요하게 코드를 스프링에 연결하기 때문에 사용하지 않는 것이 좋습니다 . 다른 방법으로는 @PreDestroy주석을 사용하거나 Bean 정의가 지원하는 일반적인 메소드를 지정하는 것이 좋습니다 . XML 기반 구성 메타데이터를 사용하여 <bean/> 의 속성인 destroy-method 을 사용할 수 있습니다. Java 구성을 사용하면의@Bean 의 속성인 destroyMethod을 사용할 수 있습니다 . 라이프 사이클 콜백 수신을 참조하십시오 . 다음 정의를 고려하십시오.

<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {

    public void cleanup() {
        // do some destruction work (like releasing pooled connections)
    }
}

앞의 정의는 다음 정의와 거의 동일한 효과를냅니다.

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean {

    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}

그러나 앞의 두 정의 중 첫 번째는 코드를 Spring에 연결하지 않는다.

: 이것도 안쓴다는 말 같음.

<bean> 요소의 속성 destroy-method에 특별한 (유추 된) 값을 할당 할 수 있습니다. 이 값은 Spring에게 특정 bean 클래스에 대한 public close또는 shutdown메소드 를 자동으로 감지하도록 지시 합니다. (따라서 java.lang.AutoCloseablejava.io.Closeable구현하는는 모든 클래스는 일치합니다. ) <beans>요소의 default-destroy-method속성에 이 특별한 (추론 된) 값을 설정하여 이 동작을 전체 bean 세트에 적용 할 수도 있습니다 (기본 초기화 및 메소드 삭제 참조 ). 이것은 Java 구성의 기본 동작입니다.

기본 초기화 및 메소드 삭제

Spring 고유의 InitializingBeanDisposableBean 콜백 인터페이스 사용하지 않는 초기화 및 파괴 메소드 콜백 때, 전형적으로 init(), initialize(), dispose(), 등등과 같은 이름을 가진 메소드를 사용한다. 이상적으로, 라이프 사이클 콜백 메소드의 이름은 프로젝트 전체에서 표준화되어 모든 개발자가 동일한 메소드 이름을 사용하고 일관성을 보장합니다.

Spring 컨테이너가 모든 bean에서 이름이 지정된 초기화와 콜백 메소드 이름을 "Look"하도록 설정할 수 있습니다. 즉, 응용 프로그램 개발자는 init()이라는 초기화 콜백을 사용하여 각 bean 정의에 init-method="init" 속성을 구성 할 필요없이 응용 프로그램 클래스를 작성하고 초기화 콜백을 사용할 수 있습니다. Spring IoC 컨테이너는 빈이 생성 될 때 (그리고 앞에서 설명한 표준 라이프 사이클 콜백 계약에 따라)이 메소드를 호출한다 . 또한 이 기능은 초기화 및 메소드 콜백 삭제에 대해 일관된 명명 규칙을 적용합니다.

초기화 콜백 메소드의 이름이 init()지정 되고 destroy 콜백 메소드의 이름이 destroy()라고 지정되었다고 가정하십시오. 그런 다음 클래스는 다음 예제의 클래스와 유사합니다.

public class DefaultBlogService implements BlogService {

    private BlogDao blogDao;

    public void setBlogDao(BlogDao blogDao) {
        this.blogDao = blogDao;
    }

    // this is (unsurprisingly) the initialization callback method
    public void init() {
        if (this.blogDao == null) {
            throw new IllegalStateException("The [blogDao] property must be set.");
        }
    }
}

그런 다음 다음과 같은 bean에서 해당 클래스를 사용할 수 있습니다.

<beans default-init-method="init">

    <bean id="blogService" class="com.something.DefaultBlogService">
        <property name="blogDao" ref="blogDao" />
    </bean>

</beans>

최상위 <beans/>요소 속성에 default-init-method속성이 존재하면 Spring IoC 컨테이너가 초기화 메소드 콜백으로 bean 클래스에서 init이라는 메소드를 인식하게됩니다. Bean이 작성되고 어셈블 될 때 Bean 클래스에 이러한 메소드가 있으면 적절한 시간에 호출됩니다.

최상위 <beans/>요소에서 default-destroy-method 의 속성을 사용하여 비슷하게 destroy 메소드 콜백을 구성 할 수 있습니다 (XML의 경우) .

기존 Bean 클래스가 이미 규칙에 따라 이름이 지정된 콜백 메소드를 가지고있는 경우 , <bean/>자체의 init-methoddestroy-method 속성을 사용하여 메소드 이름을 (XML로) 지정함으로써 디폴트를 오버라이드(대체) 할 수있다.

Spring 컨테이너는 bean이 모든 의존성을 제공받은 직후에 구성된 초기화 콜백이 호출되도록 보장한다. 따라서 초기화 콜백은 raw bean 참조에서 호출됩니다. 즉, AOP 인터셉터 등은 아직 bean에 적용되지 않습니다. 대상 빈을 먼저 생성 한 다음 인터셉터 체인을 사용하여 AOP 프록시 (예)를 적용합니다. 타겟 빈과 프록시가 따로 정의되어 있다면 코드는 프록시를 거치지 않고 raw 타겟 빈과 상호 작용할 수있다. 따라서 init메소드 인터셉터에를 적용하는 것은 일관성이 없습니다. 그렇게하면 대상 빈의 라이프 사이클을 프록시 또는 인터셉터에 연결하고 코드가 원시 타겟 빈과 직접 상호 작용할 때 이상한 의미를 남길 수 있기 때문입니다.

라이프 사이클 메커니즘 결합

Spring 2.5부터는 Bean 라이프 사이클 동작을 제어하는 ​​세 가지 옵션이 있습니다.

이러한 메커니즘을 결합하여 주어진 bean을 제어 할 수 있습니다.

Bean에 대해 여러 라이프 사이클 메커니즘이 구성되어 있고 각 메커니즘이 다른 메소드 이름으로 구성된 경우, 구성된 각 메소드는 이 노트 다음에 나열된 순서대로 실행됩니다. 그러나 둘 이상의 라이프 사이클 메커니즘에 동일한 메소드 이름 이 구성 되어 - 예를 들어 init() (예 : 초기화 메소드의경우) - 있으면 앞의 섹션 에서 설명한대로 해당 메소드가 한 번 실행 됩니다.

같은 초기화 메소드를 사용하여 동일한 bean에 대해 구성된 다중 라이프 사이클 메커니즘이 다음과 같이 호출됩니다.

  1. 주석이 달린 메소드 @PostConstruct

  2. InitializingBean로써 정의된afterPropertiesSet()콜백 인터페이스

  3. 사용자 정의 구성된 init()메소드

Destroy 메소드는 같은 순서로 호출됩니다.

  1. 주석이 달린 메소드 @PreDestroy

  2. DisposableBean로 정의 된destroy()콜백 인터페이스

  3. 사용자 정의 구성된 destroy()메소드

시작 및 종료 콜백

Lifecycle인터페이스 (예 : 시작 ,중지, 일부 백그라운드 프로세스와 같은) 자신의 라이프 사이클 요구 사항이있는 개체에 대한 필수 메소드를 정의합니다 :

public interface Lifecycle {

    void start();

    void stop();

    boolean isRunning();
}

모든 Spring 관리 객체는 Lifecycle인터페이스를 구현할 수 있습니다. 그런 다음 ApplicationContext자체가 시작 및 중지 신호 (예 : 런타임에 시나리오 중지 / 다시 시작)를 수신하면 해당 호출을 해당 컨텍스트 Lifecycle내에 정의 된 모든 구현에 계단식으로 연결합니다 . LifecycleProcessor에 위임하여 이 작업을 수행합니다. 다음과 같은 목록입니다.

public interface LifecycleProcessor extends Lifecycle {

    void onRefresh();

    void onClose();
}

the LifecycleProcessor는 그 자체가 Lifecycle 인터페이스 의 확장이다 . 또한 새로 고쳐지고 닫히는 컨텍스트에 반응하는 두 가지 다른 방법을 추가합니다.

일반 org.springframework.context.Lifecycle인터페이스는 명시적인 시작 및 중지 알림을위한 일반 계약이며 상황에 맞는 새로 고침시 자동 시작을 의미하지 않습니다. 특정 bean의 자동 시작에 대한 세부적인 제어 (시작 단계 포함)는 org.springframework.context.SmartLifecycle대신 구현 을 고려하십시오 .

또한 중지 알림은 파괴 전에 보장 할 수 없습니다. 일반 종료시 모든 LifecycleBean은 먼저 일반 파괴 콜백이 전파되기 전에 중지 알림을받습니다. 그러나 컨텍스트의 유효 기간 동안의 새로 고침 또는 중단 된 새로 고침 시도에서는 destroy 메서드 만 호출됩니다.

시작 및 종료 호출 순서가 중요 할 수 있습니다. 종속 관계는 두 객체간에 "의존 관계"가 존재하면 의존 관계 이후에 시작되며 의존 관계가 끝나기 전에 중단됩니다. 그러나 때로는 직접적인 종속성을 알 수 없습니다. 특정 유형의 객체가 다른 유형의 객체보다 먼저 시작해야한다는 것을 알 수 있습니다. 이 경우, SmartLifecycle인터페이스는 또 다른 옵션, 즉 수퍼 인터페이스에 정의 된 getPhase() 메소드로 Phased 를 정의합니다. 다음 목록은 Phased인터페이스 의 정의를 보여줍니다 .

public interface Phased {

    int getPhase();
}

다음 목록은 SmartLifecycle인터페이스 의 정의를 보여줍니다 .

public interface SmartLifecycle extends Lifecycle, Phased {

    boolean isAutoStartup();

    void stop(Runnable callback);
}

시작할 때, 가장 늦은 phase 와 있는 개체가 먼저 시작됩니다. 정지 할 때는 역순으로 진행됩니다. 따라서, SmartLifecycle을 구현하고 getPhase()메서드가 Integer를 반환하는 객체입니다. Integer.MIN_VALUE는 처음부터 시작하고 마지막으로 중지해야합니다. 스펙트럼의 다른 끝에서 위상 값은Integer.MAX_VALUE객체가 마지막으로 시작되어 먼저 중지되어야 함을 나타냅니다 (실행중인 다른 프로세스에 따라 달라질 수 있음). phase 값을 고려할 때, SmartLifecycle을 구현하지 않는 "일반" Lifecycle 개체의 기본 단계가 0임을 알아야합니다.

따라서 음의 phase 값은 객체가 이러한 표준 구성 요소보다 먼저 시작해야한다는 것을 나타냅니다. 반대의 경우는 양의 phase 값에 해당됩니다.

SmartLifecycle에 의해 정의 된 stop 메소드는 콜백 을 허용합니다. 모든 구현은 해당 구현의 종료 프로세스가 완료된 후 해당 콜백의 run()메서드를 호출해야합니다 . LifecycleProcessor 인터페이스 efaultLifecycleProcessor의 기본 구현이 해당 콜백을 호출하기 위해 각 단계 내의 객체 그룹에 대한 제한 시간 값까지 기다리기 때문에 필요에 따라 비동기식 종료가 가능합니다. 기본 단계별 시간 초과는 30 초입니다. 컨텍스트 내에서 lifecycleProcessor로 명명 된 bean을 정의하여 기본 수명주기 프로세서 인스턴스를 무시할 수 있습니다 . 제한 시간 만 수정하려면 다음을 정의하면 충분합니다.

<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
    <!-- timeout value in milliseconds -->
    <property name="timeoutPerShutdownPhase" value="10000"/>
</bean>

이전에 언급했듯이 LifecycleProcessor인터페이스는 컨텍스트의 새로 고침 및 닫기를위한 콜백 메서드를 정의합니다. 후자 stop()는 명시 적으로 호출 된 것처럼 종료 프로세스를 구동 하지만 컨텍스트가 닫힐 때 발생합니다. 반면 '새로 고침' 콜백은 SmartLifecycle빈의 다른 기능을 사용 가능하게합니다 . 모든 객체가 인스턴스화되고 초기화 된 후 컨텍스트가 새로 고쳐지면 해당 콜백이 호출됩니다. 이 시점에서 기본 수명주기 프로세서는 각 SmartLifecycle개체의 isAutoStartup()메서드에서 반환 된 부울 값을 확인합니다 . 만약 true라면, 그 객체는 문맥의 갱신이나 문맥의 갱신과는 달라, 문맥 또는 그 고유의 start()메소드의 명시적인 호출을 기다리는 것이 아니라, 그 시점에서 개시됩니다. 문맥의 개시는 표준 문맥의 구현에서는 자동적으로 일어나지 않습니다. phase값 및 "의존 "관계는 전술 한 바와 같이 시 순서를 결정한다.

웹 애플리케이션이 아닌 환경에서 Spring IoC 컨테이너를 정상적으로 종료하기

이 절은 비 웹 응용 프로그램에만 적용됩니다. Spring의 웹 기반 ApplicationContext구현은 이미 관련 웹 애플리케이션이 종료 될 때 Spring IoC 컨테이너를 정상적으로 종료하는 코드를 가지고있다.

웹 이외의 응용 프로그램 환경 (예 : 리치 클라이언트 데스크탑 환경)에서 Spring의 IoC 컨테이너를 사용하는 경우 JVM에 종료 훅을 등록하십시오. 이렇게하면 정상적인 종료가 보장되고 모든 리소스가 해제 될 수 있도록 싱글 톤 bean의 관련 destroy 메소드가 호출됩니다. 이러한 파괴 콜백을 올바르게 구성하고 구현해야합니다.

종료 훅을 등록하려면 다음 예와 같이 ConfigurableApplicationContext인터페이스에 선언 된 registerShutdownHook()메소드를 호출하십시오.

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Boot {

    public static void main(final String[] args) throws Exception {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

        // add a shutdown hook for the above context...
        ctx.registerShutdownHook();

        // app runs here...

        // main method exits, hook is called prior to the app shutting down...
    }
}

Last updated