스프링 컨테이너는 Bean객체들을 관리한다. 스프링 컨테이너를 IoC컨테이너라고도 일컫는데, 스프링 컨테이너가 IoC의 설계원칙을 따르기 때문이다.
IoC(Inversion of Control)는 이전에 언급했듯이 제어의 역전을 말한다. 즉 Bean객체들을 관리하는 주체가 개발자가 아닌 스프링 컨테이너가 대신 수행한다는 것이다.
DB 커넥션 풀이나 네트워크 소켓 연결 등 어플리케이션 시작 시점에 필요한 연결들을 미리한 뒤, 종료시점에 연결된 것들을 모두 종료하는 작업이 필요하다.
여기서 먼저 필요한 연결을 하려면 필요한 데이터를 사용할 수 있는 준비가 되어야한다. 필요한 데이터를 사용하기 위해서는 빈 객체를 생성하고 의존관계 주입을 끝낸 후에 사용가능하다. 어플리케이션 시작 시점과 종료시점을 어떻게 알 수 있을까?
스프링에서는 다행히 의존관계 주입이 완료된 후, 스프링 컨테이너가 종료되기 직전에 콜백을 통해서 알려주는 다양한 기능을 제공해준다. 스프링에서 제공하는 기능을 통해서 손쉽게 콜백을 받을 수 있다.
💡 콜백(Callback)
콜백함수를 부를때 사용되는 용어로 특정이벤트가 발생했을 때 해당 메소드가 호출(비동기)된다.
초기화 콜백
: 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출소멸 전 콜백
: 빈이 소멸되기 직전에 호출라이프 사이클을 보면 스프링 빈 생성, 의존관계 주입, 초기화 콜백이 나누어진 것을 볼 수 있다. 생성자 주입을하면서 빈을 생성하고 생성자 주입 내에서 초기화 콜백을 수행하면 될 것같은데 분리 되어있다.
💡 객체의 생성과 초기화의 분리
초기화 작업에서 값들의 변경이 적거나 코드가 전체적으로 단순할 때는 라이프 사이클을 압축해서 생성자 주입때 한번에 처리하는 것이 더 효율적일 수 있다.
그러나 코드가 단순한 경우가 아니라면 초기화 작업에는 생성자에서 생성된 객체의 값들을 활용해서 외부 커넥션을 연결하는 등 무거운 동작을 수행하는데, 생성자안에서 이런 복잡한 과정들을 한꺼번에 작성하는 것보다 생성과 초기화 부분을 분리하면 유지보수 관점에서 훨씬 효율적이다.
인터페이스 InitializingBean
, DisposableBean
을 상속바당 구현체를 작성하는 방식으로, InitializingBean
은 메소드를 초기화하는 초기화 콜백
을 지원한다. 그리고 DisposableBean
은 메소드 소멸 전 콜백
을 지원한다.
사용법은 다음과 같다
| BeanCallbackEx
public class BeanCallbackEx implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
connect();
call("초기화 콜백");
}
@Override
public void destroy() throws Exception {
disconnect();
}
}
→ 인터페이스를 사용하는 방법은 스프링 초창기 출시된 방법으로 지금은 거의 사용되지 않는다.
설정 정보에서 메서드를 지정하면 인터페이스 방식의 단점이었던 메서드 명의 변경불가, 스프링 인터페이스에 의존, 외부라이브러리의 적용불가를 모두 해결할 수 있다. 먼저 코드로 알아보자
| BeanCallbackConfig
public class BeanCallbackConfig {
@Bean(initMethod = "init", destroyMethod = "close") // 빈 등록 시점에 초기화 메서드, 종료메서드 지정
public BeanCallback beanCallback() {
...
}
}
| BeanCallbackEx
public class BeanCallbackEx {
public void init() {
connect();
call("초기화 콜백");
}
public void close() {
disconnect();
}
}
설정정보에서 지정해주는 방식은 스프링 빈을 등록할 때 초기화 메소드와 종료 메소드를 지정할 수 있다. 설정 정보 중 destroyMethod
속성에는 아주 특별한 기능이 있다. 이 특별한 기능은 추론 기능
인데 destryMethod
의 기본값이 inferred(추론)
으로 등록되어 있다.
라이브러리에서 종료 메서드의 메서드명은 대부분 close
또는 shutdown
을 사용하는데 이 추론 기능이 close
와 shutdown
의 이름을 가지고 있는 메서드를 자동으로 호출해주는 기능이다. 그렇기 때문에 종료 메서드를 따로 설정하지 않아도 종료메서드를 호출해서 동작시킨다.
만약 이 추론 기능을 사용하지 않으려면 destryMethod=""
으로 지정하면 된다.
@PostConstruct
와 @PreDestroy
애너테이션을 사용하는 방식이 최신 스프링에서 가장 권장하는 방법이다. 구성정보 클래스에서 따로 작성해주지않고 메서드에 애너테이션 하나만 작성하면 되므로 매우 편리하다.
또한 javax.annotation.*
패키지에 속해 있는 기능으로 스프링 종속 기능이 아니라 JSR-250
이라는 자바표준 기술로 스프링 환경이 아니어도 동작하며 컴포넌트 스캔과 함께 사용할 수 있다.
하지만 인터페이스를 사용할 때의 단점이었던 커스터마이징이 불가능한 외부라이브러리에서 적용이 불가하다는 단점이 있어 외부 라이브러리에서 작동시켜야 할 경우는 위의 설정정보에서 지정
하는 방식을 채택해서 사용해야 한다.
사용 코드는 다음과 같다.
| BeanCallbackEx
public class BeanCallbackEx {
@PostConstruct
public void init() throws Exception {
connect();
call("초기화 콜백");
}
@PreDestroy
public void close() throws Exception {
disconnect();
}
}