위의 간단한 예제를 통해 알아보도록 하겠습니다.
AnnotationConfigApplicationContext
를 통해 컨테이너 초기화가 됩니다.
컨테이너가 초기화가 완료되면 사용가능한 상태가 되고
getBean
을 통해 bean을 가져다 사용할 수 있습니다.
Bean의 사용이 끝나면 close
를 통해 컨테이너의 소멸처리가 됩니다.
이러한 컨테이너의 초기화 -> 사용 -> 종료 가 일어날 때 bean은 어떤 라이프라이클 과정을 거치게 될까요?
컨테이너가 초기화될 때 bean의 라이프사이클도 시작됩니다.
@Bean
을 검색합니다.@Bean
이 등록되고 bean의 객체가 생성됩니다.*Aware
인터페이스가 순차적으로 호출됩니다.aware인터페이스는 본래 spring내부에서 사용하기 위해 만들어졌지만, bean이 컨테이너의 정보 (id, name 등)에 접근하기 위해서는 필요한 Aware를 상속받아 원하는 기능을 구현할 수 있습니다.
다만 ApplicationContextAware
를 상속받아 처리하면 Spring에 의존이 강하게 생기므로 가능하면 지양해야 합니다.
*Aware
의 인터페이스가 순차적으로 호출이 끝나면 초기화 과정이 일어납니다.어노테이션 -> 인터페이스 상속 -> @Bean 선언
의 순으로 초기화 메서드가 실행됩니다.
선언하지 않았거나 상속받지 않았을 경우 당연히 호출되지 않습니다.
여기까지 진행되면 Bean은 사용가능한 상태가 됩니다.
즉, 컨테이너의 getBean
을 통해 불려와지고 정상 사용이 가능합니다.
모든 사용이 끝나고 컨테이너가 close
를 통해 소멸될 때
Bean역시 소멸의 라이프 라이클을 가지게 됩니다.
어노테이션 -> 인터페이스 상속 -> @Bean 선언
의 순서로 소멸 함수가 실행됩니다.초기화와 소멸 과정에서 호출되는 메서드들에 대해 좀 더 자세히 살펴보겠습니다.
Bean의 생성/소멸 시 메서드 실행하기
Bean이 생성되고 소멸될 때 필요한 함수를 실행하기 위해서는 상속 또는 메서드를 지정해주면 필요한 처리를 할 수 있습니다.
이렇게 생셩/소멸 시 처리해야할 작업으로는 db connection을 관리한다던가, 채팅의 경우 socket 연결/종료 등의 작업을 할 수 있습니다.
먼저 어노테이션을 이용해 생성/소멸이 필요한 처리를 할 수 있습니다.
Service 클래스 안에서 생성시, 소멸시 실행 될 함수에
@PostConstruct
를 통해 생성시 실행할 메서드
@PreDestory
를 통해 소멸시 실행할 메서드를
지정할 수 있습니다.
이렇게 지정하고 실행해보면 위 캡쳐와 같이 init -> 함수 실행 -> destory 가 순차적으로 실행되는것을 확인할 수 있습니다.
어노테이션으로 지정하는 방식은 java 9버전부터 deprecated
된 기능이고, java 11에서부터는 제거된 기능입니다.
지금 사용하려고 하면 찾을 수 없는 어노테이션이라는 오류를 볼 수 있을것입니다!
InitializingBean
과 DesposableBean
을 상속받아 처리하는 방법이 있습니다.
위 인터페이스 선언을 보면
InitializingBean
은 aterPropertiseSet
을 호출하고
DesposableBean
은 destory
를 호출하는것을 볼 수 있습니다.
두 개의 인터페이스를 상속받아 aterPropertiseSet
, destory
함수를 override하여 재정의한 후 필요한 처리를 할 수 있습니다.
인터페이스를 상속받아 처리하는 방법은 spring에 의존성이 생기기 때문에 추천하지는 않는 방법입니다.
@Bean 선언 시 초기화, 소멸 시 실행할 함수를 지정하는것도 가능합니다.
@Bean(initMethod = "foo", destoryMethod = "bar")
와 같은 방법으로 지정이 가능하며, 꼭 쌍으로 둘 다 지정해줘야하는것은 아니며 필요한 것만 지정하는것도 가능합니다.
예를들어 @Bean(initMethod = "foo")
와 같이 사용하는것도 문제없습니다.
생성/소멸 시 실행 할 함수를 우선 생성해두고 (init
과 destory
)
@Bean 선언시 호출 할 함수를 지정해주고 프로그램을 실행해보면
역시 순서대로 잘 호출되는것을 볼 수 있습니다.
이렇게 @Bean에 호출할 함수를 지정하는 방식은 프로젝트 내에 코드를 가지고있지 않은경우. 예를들어 외부 라이브러리를 가져다 사용했을 경우 외부 라이브러리의 초기화, 소멸을 여기서 호출해줄 수 있습니다.
Bean을 선언할 때 Scope
의 범위를 지정하지 않으면 default로는 singleton으로 생성됩니다. 즉 getBean을 호출할 때마다 새로운 인스턴스를 생성하는것이 아니라 싱글톤으로 리턴되도록 Spring에서 관리해줍니다.
이는 개발자의 Scope
의 선언을 통해 범위를 지정해줄 수 있습니다.
Scope | 설명 |
---|---|
singleton | 기본(Default) 싱글톤 스코프. 하나의 Bean 정의에 대해서 Container 내에 단 하나의 객체만 존재 |
prototype | 어플리케이션에서 요청시 (getBean()) 마다 스프링이 새 인스턴스를 생성 |
request | HTTP 요청별로 인스턴스화 되며 요청이 끝나면 소멸 |
session | HTTP 세션별로 인스턴스화되며 세션이 끝나며 소멸 |
global session | 하나의 Bean 정의에 대해서 전역적인 HTTP session의 라이프사이클이 되는 범위 |
사용하는 방법은
@Bean
@Scope("prototype")
와 같이 사용할 수 있습니다.
prototype
으로 선언할 경우 위 설명처럼 getBean
을 호출할 때마다 새로운 인스턴스가 생성되고 주의해야할점은 리소스 해제에 대해 개발자가 직접 처리해줘야 합니다.
위 Bean의 라이프사이클에서 소멸과정 (destory)가 Scope를 prototype으로 지정하면 호출되지 않습니다.
이는 개발자에게 소멸에 대한 처리를 구현할 책임을 주고 있습니다.