스프링 빈의 생성자, afterPropertiesSet(), @PostConstruct 의 차이점과 용도에 대해 알아보겠습니다.
자바 클래스의 인스턴스가 생성되는 시점에 필요한 작업이 있다면 대부분 생성자에서 이루어지며 주로 아래와 같이 멤버 변수의 값을 지정하는 역할을 하게 됩니다.
class Book {
private String title;
private String content;
Book() {
title = "Unknown Title";
content = "Unknown Content";
}
Book(String title, String content) {
this.title = title;
this.content = content;
}
}
그런데 Java에는 @PostConstruct 라는 애노테이션이 있습니다. 이름만 보았을때는 생성자와 유사한 역할을 수행할 것 같은데 굳이 생성자가 아닌 별도의 메소드에서 처리할 일에는 어떤것이 있을까 알아보기로 했습니다.
java 공식문서를 보면 의존성 주입이 끝난 뒤 실행될 메소드에 적용하라고 되어있습니다. 추가적으로 @PostConstruct 는 의존성 주입을 지원하는 클래스에서 무조건 지원해야 하며 해당 클래스에 주입받을 의존성이 없는 경우에도 동일한 시점에 실행되어야 한다 라는 설명이 있었습니다.
일반 자바 클래스의 인스턴스에서 어떤 의미인지는 모르겠으나 스프링 의존성 주입 시점과 관련이 있다는 사실을 알게 되었습니다. (JSR-250 의 스펙이기 때문에 이를 지원하는 다른 프레임워크에서도 사용할 수 있습니다.)
아래 예제에서 볼 수 있듯 생성자를 호출하는 시점에는 의존성 주입이 이루어지지 않기 때문에 주입받은 의존성에 대한 작업이 필요할 경우 @PostConstruct 가 적용된 메소드에서 이루어져야 합니다. 또한 @PostConstruct 가 적용된 메소드는 Bean LifeCycle 안에서 한번만 수행될 것이 보장되기 때문에 프록시 사용 등의 이유로 프레임워크 내에서 생성자의 호출이 여러번 발생할 경우 고려해볼 수 있겠습니다.
class Foo {
@Autowired
Bar bar;
Foo() {
System.out.println(bar); // null
System.out.println("bar does not injected");
}
@PostConstruct
public void barInit() {
System.out.println(bar); // package.Bar@...
System.out.println("bar is injected.");
}
}
다만 java 9 부터 @PostConstruct 가 Deprecated 되었으니 java 9 이상을 사용할 경우 아래에서 설명할 afterPropertiesSet()을 고려해봐야 할 것 같습니다.
afterPropertiesSet() 은 InintializingBean 인터페이스의 메소드로 BeanFactory에 의해 모든 property 가 설정되고 난 뒤 실행되는 메소드입니다. 주로 실행시점의 custom 초기화 로직이 필요하거나 주입받은 property 를 확인하는 용도로 사용됩니다.
조금 더 자세한 실행 시점은 BeanFactory의 공식문서 에서 확인할 수 있습니다.