티스토리 뷰

반응형

[배워서 바로 쓰는 스프링 프레임워크 - www.yes24.com/Product/Goods/90051375]

 

1. 소개

  • 이 장에서 다루는 내용
    • 빈 정의 상속
    • 빈 클래스의 생성자 인수를 찾는 방법
    • 원시 타입(int, float 등)이나 컬렉션 타입(java.util.List, java.util.Map 등) 또는 사용자 정의 타입(Address 등)을 사용해 빈 프로퍼티나 생성자 인수를 설정하는 방법
    • 빈 프로퍼티에 p-이름공간(namespace), 생성자 인수에 c-이름공간을 활용해서 XML 파일을 좀 더 간결하게 만든느 방법
    • 빈 인스턴스를 생성하는 팩토리 클래스를 작성할 때 사용하는 스프링 FactoryBean ㅣㅇㄴ터페이스
    • 빈 설정 모듈화하기

2. 빈정의 상속

2.1 빈 정의 상속 예제

  • 애플리케이션의 여러 빈이 같은 설정 집합(프로퍼티, 생성자 인수 등)을 공유한다면 다른 빈 정의의 부모 역할을 하는 빈 정의를 만들 수 있다
  • <bean> 엘리먼트의 parent 속성으로 상속할 빈 정의의 이름을 지정
  • <bean> 엘리먼트의 abstract 속성을 true로 만들면 그 빈이 추상 빈이라는 뜻이다
    • 추상 빈에 의존하는 빈은 정의할 수 없다
    • class 속성을 지정하지 않는 빈은 꼭 추상 빈으로 만들어야 스프링 컨테이너가 그 빈 인스턴스를 생성하지 않는다

2.2 상속할 수 있는 정보

  • 부모 빈 정의가 자식 빈 정의로 상속할 수 있는 생성 정보
    • 프로퍼티 - <property> 엘리먼트로 설정
    • 생성자 인수 - <constructor-arg> 엘리먼트 설정
    • 메서드 오버라이드
    • 초기화와 정리 메서드
    • 팩토리 메서드 - <bean> 엘리먼트의 factory-method 속성으로 설정
  • 부모 빈정의가 추상이 아닌 경우
    • 부모 빈 정의가 추상이 아니어도 된다
    • 자식 빈 정의에서 프로퍼티를 추가 정의할 수 있다
    • 부모 빈 정의가 참조하는 클래스와 자식 빈 정의가 참조하는 클래스 사이에서 상속 관계가 존재할 수 있다
  • 팩토리 메서드 설정 상속하기
    • 자식 빈 정의는 빈 상속을 활용해 팩토리 메서드 정의를 부모 빈 정의에서 상속할 수 있다

3. 생성자 인수 매치하기

3.1 <constructor-arg> 엘리먼트를 사용해 빈 참조나 단순한 값 전달하기

  • 생성자 인수가 간단한 자바 타입(int, String 등)이라면 <constructor-arg> 엘리먼트의 value 속성을 사용해 생성자 인수값을 지정한다
  • 생성자 인수가 빈에 대한 참조라면 <constructor-arg>의 ref 속성을 사용해 빈 이름을 지정한다

3.2 타입으로 생성자 인수 매치시키기

  • <constructor-arg> 엘리먼트의 index 속성을 지정하지 않으면 스프링 컨테이너는 <constructor-arg> 엘리먼트에 의해 참조되는 타입을 빈 클래스 생성자의 인수 타입과 매치 시켜서 어떤 생성자 인수를 호출할지 결정한다
  • 타입이 명확히 다른 스프링 빈을 생성자 인수로 사용하기
    • 타입이 근본적으로 서로 다르면(각 타입 간에 서로 상속 관계가 없다면) 타입을 모두 구분할 수 있으므로 스프링 컨테이너는 생성자에 올바른 순서로 각 빈을 주입할 수 있다
  • 상속 관계인 스프링 빈들을 생성자 인수로 사용하기
    • 서로 상속 관계인 빈을 구분하려면 index나 type 속성을 지정해서 어떤 <constructor-arg>를 어떤 생성자 인수로 적용할지 구별해야 한다
    • 둘 이상의 생성자 인수가 같은 타입인 경우 구분할 수 있는 유일한 방법은 index thrtjddmf tkdydgksms rjt Qnsdlek
  • 표준 자바 타입과 사용자 지정 타입을 생성자 인수로 사용하기
    • <constructor-arg> 엘리먼트의 value 속성을 사용해 인수값 지정
    • value 속성에 지정된 문자열을 가지고 변환할 수 있는 생성자 인수가 2개 이상이라면 type 속성을 사용해 생성자 인수 타입을 명확히 지정해야 한다
    • 생성자 인수의 타입이 같다면(둘 이상), index 속성을 사용해 각 <constructor-arg>를 어떤 생성자 인수로 적용할지 지정하는 수 밖에 없다

3.3 이름으로 생성자 인수 매치시키기

  • <constructor-arg>의 name 속성을 사용하면 <constructor-arg> 엘리먼트를 적용할 생성자 인수의 이름을 지정할 수 있다
  • 이와 같은 설정은 클래스를 컴파일할 때 디버그 플래그(javac의 -g 옵션 참조)나 파라미터 이름 발견(parameter name discovery) 플래그(자바 8 이상에서 javac의 -parameters 옵션 참조)를 사용한 경우에만 쓸 수 있다
    • 이 플래그들을 활성하하고 싶지 않다면 @ConstructorProperties를 사용해 생성자 인수 이름을 명시한다
    • <constructor-arg> 엘리먼트와 @ConstructorProperties에서 같은 이름을 사용해야 한다
  • @ConstructorProperties와 빈 정의 상속
    • 부모 빈 정의에 해당하는 클래스 생성자에 @ConstructorProperties가 있으면 자식 빈에 해당하는 빈 클래스 생성자에도 반드시 @ConstructorProperties가 있어야 한다
  • @ConstructorProperties와 팩토리 메서드
    • 정적 팩토리 메서드나 인스턴스 팩토리 메서드에 인수를 이름으로 지정해서 넘기기 위해 @ConstructorProperties를 사용할 수는 없다
    • @ConstructorProperties는 생성자만을 위한 것이므로 메서드에 @ConstructorProperties를 설정할 수 없다
    • 정적 팩토리 메서드나 인스턴스 팩토리 메서드에 이름을 가지고 생성자 인수를 전달할 경우에는 디버그나 '파라미터 이름 발견' 플래그를 활성화할 수 밖에 없다

4. 다른 타입의 빈 프로퍼티와 생성자 인수 설정하기

  • 스프링 PropertyEditor 구현
    • 다양한 타입을 빈 프로퍼티나 생성자 인수로 쉽게 넘길 수 있도록 지원해줌

4.1 스프링 내장 프로퍼티 에디터

  • 자바빈의 PropertyEditor : 자바 타입을 문자열값으로 바꾸거나 역방향으로 바꾸기 위해 필요한 로직 제공
  • 스프링은 프로퍼티나 생성자의 실제 자바타입과 빈 프로퍼티나 생성자 인수의 문자열 값(<property>나 <constructor-arg>)을 상호 변환해주는 몇가지 내장 PropertyEditor를 제공한다
  • 스프링 컨테이너는 등록된 PropertyEditor를 사용해 프로퍼티나 생성자 인수의 문자열값을 그에 상응하는 자바 타입으로 변환한다
  • 스프링은 XML 파일에 지정한 문자열값을 빈 프로퍼티나 생성자 인수의 자바 타입으로 변환하기 위한 내장 PropertyEditor 구현을 제공한다
    • CustomBooleanEditor : 문자열값을 Boolean이나 boolean 타입으로 변환한다
    • CustomNumberEditor : 문자열값을 수 타입(int, long 등)으로 변환한다
    • CharacterEditor : 문자열값을 char 타입으로 변환한다
    • ByteArrayPropertyEditor : 문자열값을 byte[] 타입으로 변환한다
    • CustomDateEditor : 문자열값을 java.util.Date 타입으로 변환한다
    • PropertiesEditor : 문자열값을 java.util.Properties 타입으로 변환한다

4.2 컬렉션 타입에 값 지정하기

  • java.util.Properties 타입
    • <constructor-arg> 엘리먼트의 <props> 하위 엘리먼트로 설정
    • <props> 엘리먼트 안에서 각 <prop> 하위 엘리먼트는 키-값 쌍을 지정
    • key 속성은 키를 설정하고, <prop> 엘리먼트의 내용은 키에 해당하는 값을 설정
  • java.util.List 타입
    • <constructor-arg> 엘리먼트의 <list> 하위 엘리먼트로 설정
    • <list> 엘리먼트 안의 각 <value> 하위 엘리먼트는 리스트에 들어갈 원소 지정
  • java.util.Map 타입
    • <constructor-arg> 엘리먼트의 <map> 하위 엘리먼트로 설정
    • <map> 엘리먼트 하위 엘리먼트인 <entry> 엘리먼트는 Map에 저장될 키-값 쌍을 지정
    • <entry> 안의 <key> 엘리먼트는 키를 설정하고 <value> 엘리먼트는 키에 해당하는 값을 설정
  • java.util.Set 타입
    • <constructor-arg> 엘리먼트의 <set> 하위 엘리먼트로 설정
    • <set> 엘리먼트의 하위 엘리먼트인 <value> 엘리먼트는 Set에 들어갈 원소를 지정
  • <list>, <set>, <map>, <prop> 엘리먼트는 자기 안에 자기 자신과 같은 타입이나 <list>, <set>, <map>, <prop>을 넣을 수 있다(키-값 쌍일 경우 키, 값 둘 다 가능)
  • 스프링 빈의 참조를 List나 Set, Map 타입의 프로퍼티나 생성자 인수에 넣을 수 있다
    • <ref> 엘리먼트 사용해 참조를 넣음
  • 빈 이름(<bean> 엘리먼트의 id 속성으로 지정)을 List, Map, Set 타입의 생성자 인수나 빈 프로퍼티에 추가하려면 <idref> 엘리먼트를 <map>, <set>, <list> 엘리먼트 안에 사용해야 한다
    • <value> 대신 <idref>를 사용하면 애플리케이션이 실행될 때 스프링 컨테이너가 sampleBean이라는 이름의 빈이 있는지 검증할 수 있다
  • <null> 엘리먼트를 사용해 null 값을 Set나 List, Map 타입의 컬렉션에 추가할 수 있다

4.3 배열에 값 지정하기

  • <property>, <constructor-arg> 엘리먼트 내부에 <array> 하위 엘리먼트를 사용해 배열 타입의 프로퍼티/생성자 인수 값을 설정할 수 있다
  • <array> 엘리먼트의 <value> 하위 엘리먼트는 배열의 원소를 표현한다
  • 배열의 배열을 만들고 싶으면 <array> 엘리먼트 안에 <array> 엘리먼트를 사용한다

4.4 <list>, <set>, <map> 엘리먼트의 디폴트 구현

  • 디폴트 컬렉션 구현
    • <list> - java.util.ArrayList
    • <set> - java.util.LinkedHashSet
    • <map> - java.util.LinkedHashMap
  • 디폴트 구현이 아닌 다른 구현을 사용할 수 있음
    • 스프링에서는 util 스키마에 <list>, <map>, <set> 엘리먼트를 사용할 것을 권장
  • <list>, <map>, <set> 엘리먼트는 빈의 생성자 인수나 프로퍼티에 대입하려는 구체적인 컬렉션 클래스의 완전한 이름을 지정하기 위한 옵션을 제공함

5. 내장 프로퍼티 에디터

  • 스프링은 빈 프로퍼티나 생성자 인수를 설정할 때 유요한 여러 가지 내장 프로퍼티 에디터를 제공한다

5.1 CustomCollectionEditor

  • 원본 컬렉션 타입을 대상 컬렉션 타입으로 변환할 때 쓰임
  • 기본적으로 Set, SortedSet, List 타입에 대해 등록되어 있음
  • 예시 - <property>에 <set> 엘리먼트를 List로 변환할 때 CustomCollectionEditor가 LinkdeHashSet을 ArrayList로 바꿔줌
  • 프로퍼티나 생성자 인수의 타입이 구체적인 컬렉션 클래스인 경우 CustomCollectionEditor는 단순히 구체적인 클래스의 인스턴스를 만들고 원본 컬렉션의 원소를 추가한다

5.2 CustomMapEditor

  • 원본 Map 타입을 대상 Map 타입으로 변환
  • 기본적으로 SortedMap 타입에 대해서만 등록되어 있음

5.3 CustomDateEditor

  • java.util.Date 타입의 프로퍼티와 생성자 인수를 위한 프로퍼티 에디터
  • java.util.Date 타입을 문자열로 형식화
  • 날짜/시간을 표현하는 문자열을 parsing해서 java.util.Date 타입의 객체를 만들 때 쓰이는 사용자 지정 java.text.EdateFormat을 지원

6. 스프링 컨테이너에 프로퍼티 데이터 등록하기

  • BeanWrapperImpl 클래스틑 몇 가지 내장 프로퍼티 에디터를 스프링 컨테이너에 등록한다
    • 기본적으로 CustomCollectionEditor, CustomMapEditor, CurrencyEditor, ByteArrayPropertyEditor, CharacterEditor가 등록됨
    • CustomDateEditor는 등록되지 않음
  • CustomEditorConfigurer : 프로퍼티 에디터를 스프링 컨테이너에 등록하기 위해 사용
    • 스프링의 BeanFactoryPostProcessor 인터페이스를 구현하고 스프링 컨테이너는 자동으로 CustomEditorConfigurer를 감지해 실행시킨다
  • 프로퍼티 에디터를 스프링 컨테이너에 등록하는 순서
    • 1. 스프링의 PropertyEditorRegistrar 인터페이스를 구현한 클래스를 만든다. 클래스는 스프링 컨테이너에 프로퍼티 에디터를 등록한다
    • 2. XML 파일에 PropertyEditorRegistrar 구현을 스프링 빈으로 등록한다
    • 3. XML 파일에 스프링의 CustomEditorConfigurer 특별 빈을 설정한다. 이때 1단계와 2단계에서 만든 PropertyEditorRegistrar 구현에 대한 참조를 지정한다

6.1 PropertyEditorRegistrar 구현 만들기

public class MyPropertyEditorRegistrar implements PropertyEditorRegistrar {
	@Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
    	registry.registerCustomEditor(Date.class,
        	new CustomDateEditor(new SimpleDdateFormat("dd-MM-YYYY"), flase));
    }
}
  • PropertyEditorRegistrar의 registerCustomEditors 메서드는 registerCustomEditor를 사용해 스프링 컨테이너에 빈 프로퍼티 에디터를 등록하는 PropertyEditorRegistry 인스턴스를 받는다

6.2 CustomEditorConfigurer 클래스 설정하기

<bean id="myPropertyEditorRegistrar"
	class="sample.spring.chapter03.beans.MyPropertyEditorRegistrar" />
<bean id="editorConfigurer"
	class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property> name="propertyEditorRegistrars">
    	<list>
        	<ref bean="myPropertyEditorRegistrar">
        </list>
    </property>
</bean>

 

7. 이름공간으로 빈 정의를 간결하게 만들기

  • XML 파일의 빈 정의에서 <property>와 <constructor-arg> 원소 대신에 p와 c라는 이름공간으로 빈 프로퍼티와 생성자 인수값을 지정할 수 있다

7.1 p-이름공간

  • 빈 프로퍼티를 <bean> 엘리먼트의 속성으로 지정하되 이름공간을 p-이름공간으로 지정
  • 빈 정의는 p 접두사를 사용해 빈 프로퍼티를 설정
  • 형식
    • p:<propterty-name>="<property-value>"
    • p:<property-name>-ref="<bean-reference>"
  • 프로퍼티 설정은 <property> 엘리먼트와 p-이름공간을 혼용할 수도 있지만 한가지로 일관성 있게 사용하는 것을 권장

7.2 c-이름공간

  • 생성자 인수를 c-이름공간에 설정하려면 <bean> 엘리먼트의 속성으로 생성자 인수를 지정하되 각각의 생성자 인수를 c-이름공간 안에 지정한다
  • 빈 정의는 c라는 접두사를 사용해 생성자 인수를 지정한다
  • 형식
    • c:<생성자-인수-이름>="<생성자-인수-값>"
    • c:<생성자-인수-이름>-ref="<빈-참조>"
  • 생성자 인수를 지정하기 위해 c-이름공간과 <constructor-arg> 엘리먼트를 함께 사용할 수 있지만 한가지로 일관성 있게 사용하는 것을 권장

8. util 스키마

  • 스프링의 util 스키마를 사용하면 일반적인 설정 작업을 쉽게 수행할 수 있어서 빈 설정이 편해진다
  • util 스키마가 제공하는 엘리먼트
    • <list> : java.util.List 타입의 객체를 만들어 빈으로 노출한다
      • list-class 속성 : java.util.List 인터페이스의 구체적인 클래스 지정(디폴트는 java.util.ArrayList)
      • <value> 엘리먼트로 리스트에 원소 추가
      • List 인스턴스를 다른 빈의 의존 관계로 지정할 수 있음
      • ListFactoryBean을 대신 사용할 수도 있음
    • <map> : java.util.Map 타입의 객체를 만들어 빈으로 노출한다
      • map-class 속성 : java.util.Map 인터페이스의 구체적인 클래스를 지정
      • <entry> 엘리먼트로 맵에 원소 추가
      • Map 인스턴스를 다른 빈의 의존 관계로 지정할 수 있음
      • MapFactoryBean을 대신 사용할 수 있음
    • <set> : java.util.Set 타입의 객체를 만들어 빈으로 노출한다
      • set-class 속성 : java.util.Set 인터페이스의 구체적인 클래스를 지정
      • <value> 엘리먼트로 set에 원소 추가
      • Set 인스턴스를 다른 빈의 의존 관계로 지정할 수 있음
      • SetFactoryBean을 대신 사용할 수 있음
    • <properties> : 프로퍼티 파일로부터 java.util.Properties 타입의 객체를 만들어 빈으로 노출한다
      • location 속성 : properties 파일 위치 넣음
      • Properties 인스턴스를 다른 빈의 의존 관계로 지정할 수 있음
      • PropertiesFactoryBean을 대신 사용할 수 있음
    • <constant> : 지정한 자바 타입에 대해 정적 공개(public, static) 필드를 만들어 노출한다
      • static-filed 속성에서 지정한 값을 빈으로 노출
      • 어떤 필드(public static)라도 <constant> 엘리먼트의 static-field 속성을 지정하면 스프링 컨테이너의 다른 빈이 참조할 수 있다
      • FieldRetrievingFactoryBean을 대신 사용할 수 있음
    • <property-path> : 빈 프로퍼티를 빈으로 노출한다
      • path 속성으로 지정된 경로를 가져와서 빈 노출
        • 형식 : <빈이름>.<빈프로퍼티>
      • 빈을 스프링 컨텡너의 다른 빈에 주입할 수 있음
      • PropertyPathFactoryBean을 대신 사용할 수 있음

9. FactoryBean 인터페이스

  • 빈 인스턴스를 생성하는 클래스(팩토리 역할)는 스프링 FactoryBean 인터페이스로 구현한다
  • 어떤 타입의 빈을 만들지 결정하고 복잡한 검사를 수행하며 복잡한 빈 초기화 로직을 실행하는 경우 유용하다
  • FactoryBean 인터페이스에서 구현해야되는 메소드
    • getObjectType : FactoryBean 구현이 관리하는 객체의 타입을 반환
    • getObject : FactoryBean 구현이 관리하는 객체를 반환
    • isSingleton
      • true : FactoryBean 구현이 싱글턴 스코프 객체를 만드는 팩토리일 때
        • 스프링 컨테이너는 getObject가 반환하는 객체를 캐시에 넣고 그 이후 객체 요청이 들어오면 캐시에 저장한 객체를 반환
        • 스프링 컨테이너는 getObject를 단 한번만 호출
      • false : FactoryBean 구현이 프로토타입 스코프 객체를 만드는 팩토리일 때
        • 매번 객체를 요청할 때마다 getObject 메서드가 새로운 객체를 반환
  • FactoryBean 자체를 스프링 컨테이너에서 얻으려면 팩토리 빈의 이름(또는 id) 앞에 &를 붙여야 한다
    • ref 속성에 ref 속성이 가리키는 빈 이름 (또는 id) 앞에 &를 붙여야 됨
      ex) <property name="eventSenderFactoryBean" ref="&amp;eventSenderFactory>
    • 클래스에서는 &를 붙여서 얻으면됨
      ex) context.getBean("&eventSenderFactory")

10. 빈 설정 모듈화하기

  • 애플리케이션 설정을 구조화하거나 모듈화하기 위해 여러 XML 파일에 빈 설정을 나눠야 할 경우가 생김
  • <import> 엘리먼트는 resource 속성으로 지정된 XML 파일을 임포트함
    • XML 파일 위치는 <import> 엘리먼트가 위치한 XML 파일로부터 시작하는 상대적인 위치
    • 스프링 컨테이너는 XML 파일에 정의된 빈을 생성하는 과정에서 의존 관계를 해결함
반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함