스프링에서 빈의 라이플 사이클은 다음과 같다.
스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료
따라서 빈이 생성되고 의존관계가 주입이 되면 초기화가 진행된다. 따라서 개발자는 의존관계가 주입되기 전에는 해당 객체를 사용할 수 없다.
그래서 스프링은 다양한 방식으로 생명주기 콜백을 제공하는데 가장 권고하는 방식이 @PostConstruct와 @PreDestroy이다.(@Bean의 initMethod와 destroyMethod 처럼 초기화, 소멸 메서드를 지정해주는 방법도 존재한다.)
생성자는 필수 정보를 파라미터를 통해 받아, 메모리를 할다하여 객체를 생성한다. 이 때 객체를 생성하는 것이 초기화가 되는 것이 아니다. 초기화는 이렇게 생성된 값을 활용하여 외부 커넥션을 연결하는 등의 무거운 작업을 수행한다.
따라서 생성자 안에 초기화를 하는 것은 유지보수에 좋지 않고 한 메소드가 다양한 역할을 하는 것은 객체 지향에 맞지 않는다.
@Component
public class MyBean {
@PostConstruct
public void init() {
System.out.println("MyBean created!");
}
@PreDestroy
public void destroy() {
System.out.println("MyBean about to be destroyed!");
}
}
@PostContruct , @PreDestory는 빈 객체를 초기화하고 소멸시켜주는 어노테이션이다. 그래서 이 어노테이션을 이용하면 의존 관계가 주입된 후 초기화 보장해준다. 또한 스프링에 종속적인 기술이 아닌 자바 표준 기술이기 때문에 다른 컨테이너에서도 동작한다.
유일한 단점은 외부라이브러리에는 적용이 안되어 @Bean의 initMethod, destroyMethod를 사용하자!
@Service
@RequiredArgsConstructor
public class RedisService {
private final RedisTemplate<String, String> redisTemplate;
private ZSetOperations<String, String> zSetOperations;
@PostConstruct
public void init() {
zSetOperations = redisTemplate.opsForZSet();
}
}
위의 코드는 내가 redis를 이용하여 랭킹 보드를 구현할 때 작성한 코드이다. RedisService를 빈으로 등록하고 초기화 할때 @PostConstruct를 이용하여 zSetOpertations를 초기화하여 빈에 등록함으로써 싱글톤으로 zSetOpertaions를 공유하도록 만들었다.