환경 : java, springframework

 

코드

 

@Component
public class TestBean {
    @Value("${test}")
    private String test;

    private String defaultTestValue = getTest();

    public TestBean() {
        System.out.println("Constructor test = " + test);
        System.out.println("Constructor defaultTestValue = " + defaultTestValue);
    }

    @PostConstruct
    public void init() {
        System.out.println("PostConstruct test = " + test);
        System.out.println("PostConstruct defaultTestValue = " + defaultTestValue);
    }

    public String getTest() {
        return test;
    }
}

 

결과

 

Constructor test = null
Constructor defaultTestValue = null
PostConstruct test = test
PostConstruct defaultTestValue = null

 

 

원인

 

왜 이렇게 동작했는지 알려면 스프링 빈의 생명주기를 알아야 한다.

스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료

의존성 주입의 방법은 대표적으로 세가지가 있다.

  • 생성자 주입
    • 생성 시점에 의존성 모듈을 찾지 못하면 빈 생성을 하지 못한다.
    • 스프링 빈 생성시점에 동작한다
  • 필드 주입
    • 필드에 @Autowired를 붙이면 주입
    • 의존성 관계 주입 시점에 동작한다. (런타임)
  • Setter 주입 (메소드를 통한 주입)
    • 메소드에 @Autowired를 붙이면 주입
    • 의존성 관계 주입 시점에 동작한다. (런타임)
    • 의존성이 순환참조 문제 날 때, 유용하게 사용할 수 있음

 

@Value 는 필드주입과 동일하게 의존관계 주입 시점에 동작하는데, 이는 생성자 호출 시점 이후이다.

defaultTestValue 생성 타이밍은 생성자 호출 시점에 생성 되는 것이기 때문에 @Value 어노테이션이 동작하기 전이다.

초기화 콜백인 @PostConstruct 이 동작하는 시점에는 @Value 가 동작한 이후이기 때문에 필드값이 출력이 되는 것이다.

 

 

그리고 new 로 생성할 때도 주입 받을 수 없는 값이기 때문에 주의를 해야한다.

 

참고

 

javax.annotation.PostConstruct 는 스프링 종속적인 기술이 아니라 JSR-250 라는 자바 표준이다.

  • 초기화 콜백 : @PostConstruct
  • 소멸전 콜백 : @PreDestroy