본문 바로가기

SpringFramework Core - I. IoC 컨테이너/7. Bean 정의 상속

1.7. Bean 정의 상속

Bean 정의는 많은 설정 정보를 포함할 수 있다. 생성자 매개변수, 프로퍼티 값들, 컨테이너 정보, 초기화 메서드, 정적 팩토리 메소드 이름 등등이 포함된다. 자식 bean 정의는 부모 정의로부터 설정 데이터를 상속받는다. 자식 정의는 몇몇 값들을 오버라이드할 수 있으며 다른 필요한 것들을 더할 수도 있다. 부모와 자식 bean 정의를 사용하는 것은 많은 타이핑을 줄여준다. 이것이 효과적으로 템플릿화하는 방법인 것이다.

 

만약 프로그램적으로 ApplicationContext를 가지고 작업을 한다면, 자식 bean 정의들은 ChildBeanDefinition 클래스로 표현된다. 대부분의 다른 사용자들은 이 단계에서 자식 bean들로 작업하지 않는다. 대신에 그들은 ClassPathXmlApplicationContext와 같은 클래스에서 명확하게 bean 정의들을 설정해준다. 만약 XML 기반의 설정 메타데이터를 사용한다면, parent 속성을 사용하여 부모 bean의 속성값을 특정해줌으로써 자식 bean임을 가리킬 수 있다. 다음 예시가 그 방법을 보여준다.

<bean id="inheritedTestBean" abstract="true" class="org.springframework.beans.TestBean">
    <property name="name" value="parent" />
    <property name="age" value="1" />
</bean>

<bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean"
      parent="inheritedTestBean"      init-method="initialize">
    <property name="name" value="override" />
    <!-- 'age' 프로퍼티의 값인 '1'은 부모로부터 상속될 것이다 -->
</bean>

자식 bean 정의는 부모 정의의 bean 클래스를 사용할 수 있으며, 아무 것도 특정된 것이 없더라도 오버라이드할 수 있다. 후자의 경우, 자식 bean 클래스는 반드시 부모의 프로퍼티값을 수용할 수 있는 등 부모 클래스와 양립가능해야만 한다.

 

자식 bean 정의는 scope, 생성자 매개변수 값, 프로퍼티 값 등을 상속받으며 부모의 메소드를 오버라이드한다. 이 과정들 속에 새로운 값을 추가하기도 한다. 특정된 모든 scope, 초기화 메소드, 소멸 메소드, 정적 팩토리 메소드 세팅들을 오버라이드한다. 

 

남은 세팅들은 모두 자식 정의에서 오는 것들이다. depends on, autowire 모드, 의존성 체크, 싱글턴, lazy 초기화 등등.

 

위의 예시는 abstract 속성을 사용함으로써 추상 클래스로서의 부모 bean 정의를 명확하게 표시해줬다. 만약 부모 bean 정의가 클래스를 특정하지 않는다면, 부모 bean 정의를 abstract로써 명확하게 표시해야 한다. 다음 예시는 참고하자.

<bean id="inheritedTestBeanWithoutClass" abstract="true">
    <property name="name" value="parent" />
    <property name="age" value="1" />
</bean>

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
      parent="inheritedTestBeanWithoutClass" init-method="initialize">
    <property name="name" value="override" />
    <!-- 'age'는 '1'이라는 값을 부모 bean 정의로부터 상속받는다 -->
</bean>

부모 bean은 불완전하기 때문에 스스로 인스턴스화될 수 없다. 또한 명확하게 abstract라고 표시되어 있다. 정의가 abstract로 되어있으면, 오직 자식 정의들을 위해 부모로서 bean 정의를 제공하는 순수한 템플릿으로밖에 사용할 수 없다. 다른 bean에서 ref 프로퍼티를 통해 abstract한 부모 bean을 사용하거나, 부모 bean의 ID를 getBean()을 통해 명확하게 호출하는 것은 에러를 반환한다. 이와 유사하게, 컨테이너 내부의 preInstantiateSingletons() 메소드는 abstract로 정의된 bean 정의들을 무시한다.

 

  ApplicationContext는 모든 싱글턴들을 기본 설정으로 pre-instantiate한다. 그러므로 단지 템플릿으로써 사용하려는 bean 정의가 있는지, 그 정의는 클래스를 특정하고 있는지 여부는 중요하다. 반드시 abstract 속성을 true로 세팅해줘야 하는데 만약 그렇지 않으면 애플리케이션 context는 실제로 abstract bean을 pre-instantiate하려고 시도할 것이다.