Spring Container

핵심 기능

  1. 자바 객체(bean)의 라이프 사이클 관리
  2. Dependency Injection(DI)

 

종류

  1. BeanFactory interface의 구현체
    • Bean 객체를 생성하고 DI를 실행하는 기본적인 기능 제공
  2. ApplicationContext interface 및 그 sub-interface의 구현체
    • Anntation 기반 설정, Java code 기반 설정
    • 다양한 부가 기능 추가 제공

 

Spring Container의 bean 생성 및 관리

 

BeanFactory interface

  • org.springframework.beans.factory.BeanFactory
  • Spring container에 대한 기본적인 API 정의
    • <T> getBean(String name, Class requiredType) → 주어진 이름과 타입을 가진 bean 반환
    • <T> getBean(Class requiredType) → 주어진 타입을 가진 bean 반환
    • Object getBean(String name) → 주어진 이름을 가진 bean 반환 (타입 변환 필요)

 

ApplicationContext interface

  • org.springframework.beans.factory.ApplicationContext 
  • 주요 구현 클래스
    • GenericXmlApplicationContext → XML 파일을 설정 정보로 사용
    • AnnotationConfigApplicationContext → Java class의 설정 정보를 이용
    • XmlWebApplicationContext, AnnotationConfigWebApplicationContext
  • 사용 예
ApplicationContext context = new GenericXmlApplicationContext("classpath:applicationContext.xml");
BeanType bean = (BeanType) context.getBean("beanName"); // 타입 변환 필요
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanType bean = (BeanType) context.getBean("beanName"); // 타입 변환 필요
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml","config/aop.xml"); // 여러 개 가능
BeanType bean = context.getBean("beanName", BeanType.class);
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigClass.class);
BeanType bean = context.getBean("beanName", BeanType.class);

 

Bean 생성 및 사용

Bean 설정 (configuration)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=“http://www.springframework.org/schema/beans”
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
                      http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="bean ID" class="생성할 bean 객체의 class 이름(package 경로 포함)">
    <property name="bean의 property 이름">
      <value>property 값</value>
    </property>
    <property name="bean의 property 이름" ref="참조할 bean의 ID" />
  </bean> 
  <bean id="bean ID" class="생성할 bean 객체의 class 이름">
    <constructor-arg><value>생성자의 파라미터 값</value></constructor-arg>
    <constructor-arg><ref bean="참조할 bean의 ID" /></constructor-arg>
  </bean> 
</beans>
  • 2, 4행: bean 설정을 위한 기본 네임스페이스 및 스키마 위치 선언
  • 10, 14행: 의존 객체 주입
  • <beans>: 설정 파일의 루트 엘리먼트
  • <bean>: 컨테이너에 의해 생성 및 관리될 bean 객체 정의
    • id/name 속성: bean 객체들을 구분하기 위한 식별자
    • class 속성: 객체의 완전한 클래스 경로

 

Bean 객체 획득

BeanFactory 또는 ApplicationContext 객체(container)에 대해 getBean() 메서드 호출

ApplicationContext ctx = new ClassPathXmlApplicationContext("springIdol.xml");

Performer performer = (Performer) ctx.getBean("duke"); // type casting 필요
Performer performer2 = ctx.getBean("duke", Performer.class); // type 제공
  • 1행: 컨테이너 생성

 

의존 관계 설정 - 생성자 방식(constructor-based injection)

  • Bean의 생성자를 통해 의존 객체를 주입
  • 이용가능한 생성자가 bean 클래스에 정의되어 존재해야 함
  • 설정 방법
    • <constructor-arg>를 사용하여 생성자의 인자(argument) 지정
      • <value>값</value>: 기본 데이터 타입의 값 전달
      • <ref bean="bean 식별자" />: bean 객체의 참조 전달
    • <constructor-arg>의 value, ref 속성을 통해 지정
      • <constructor-arg value="값" />
      • <constructor-arg ref="bean 식별자" />
더보기

값의 타입 설정

  • <value>를 통해 전달되는 값은 기본적으로 String 타입으로 간주
  • type 속성을 이용하여 다른 타입으로 변환 설정 가능
  • <constructor-arg value="10" type="int" />
  • 효과
    • Container는 다른 bean이 의존하는 bean 객체를 먼저 생성
    • 의존 객체나 값의 타입을 이용하여 적절한 생성자를 찾아 실행
      • 의존 객체나 값과 일치하거나 가장 근접한 타입의 인자를 가진 생성자 선택
      • 생성자 호출시 의존객체/값을 인자로 전달 (DI)

Instrumentalist bean class

public class Instrumentalist implements Performer {
  private String song = "White Christmas";
  private Instrument instrument; // 초기화 되지 않음

  public Instrumentalist() { } // 생성자 1(기본 생성자)
  public Instrumentalist(Instrument instrument) { // 생성자 2
    this.instrument = instrument;
  }
  public Instrumentalist(String song, Instrument instrument) { // 생성자 3
    this.song = song;
    this.instrument = instrument;
  }
  public void perform() throws PerformanceException { // business method
    System.out.print("Playing " + song + " : ");
    instrument.play(); // 의존 객체의 method 호출 (의존 객체 필요)
  }
}

bean 설정

<bean id="saxophone" class="com.example.springidol.Saxophone" /> 
<!-- 자식 엘리먼트 표현 -->
<bean id="kenny" class="com.example.springidol.Instrumentalist">
  <constructor-arg><value>Jingle Bells</value></constructor-arg> → 값 전달
  <constructor-arg><ref bean="saxophone" /></constructor-arg> → 의존 객체 전달
</bean>

<!-- 속성으로 표현 -->
<bean id="kenny" class="com.example.springidol.Instrumentalist">
  <constructor-arg value="Jingle Bells" /> 
  <constructor-arg ref="saxophone" />
</bean>

<!-- "c" namespace 이용 -->
<bean id="kenny" class="com.example.springidol.Instrumentalist"
  c:song="Jingle Bells"
  c:instrument-ref="saxophone" />
  • Saxophone은 Instrument의 구현 클래스
  • 인자 순서 중요
  • 네임스페이스 접두사 c 선언
  • 16, 17행: 또는 c:_0, c:_1-ref (참조는 -ref 안달면 에러)

Spring container가 아래와 같이 실행 (생성자 3 이용)

Saxophone saxophone = new Saxophone();
Instrumentalist kenny = new Instrumentalist("Jingle Bells", saxophone);

 

의존 관계 설정 - Setter method 방식(setter-based injection)

  • Property에 대한 setter method를 통해 의존 객체 주입
  • bean 클래스에 property에 대한 setter method가 정의되어 있어야 함
  • 설정 방법
    • <property>를 사용하여 값이나 의존 객체 지정
      • <value>값</value>: 기본 데이터 타입의 값 전달
      • <ref bean="bean 식별자" />: 의존 객체 전달
    • <property>의 value, ref 속성을 통해 지정
      • <property value="값" />
      • <property ref="bean 식별자" />
  • 효과
    • Container는 property로 전달할 의존 객체를 먼저 생성
    • 각 property에 대한 setter method를 실행하여 객체나 값을 전달

Instrumentalist bean class

public class Instrumentalist implements Performer {
  public Instrumentalist() { } // 기본 생성자는 존재해야 함
  private String song; // property
  public void setSong(String song) { // setter method
    this.song = song;
  }
  private Instrument instrument; // property
  public void setInstrument(Instrument instrument) { // setter method
    this.instrument = instrument;
  }
  public void perform() throws PerformanceException { // business method
    System.out.print("Playing " + song + " : ");
    instrument.play();
  }
}

bean 설정

<bean id="saxophone" class="com.example.springidol.Saxophone" />
<!-- 자식 엘리먼트로 표현 -->
<bean id="kenny" class="com.example.springidol.Instrumentalist">
  <property name="song">
    <value>Jingle Bells</value> 값 전달
  </property> 
  <property name="instrument"> 
    <ref bean="saxophone" /> bean 전달
  </property> 
</bean>

<!-- 속성으로 표현 -->
<bean id="kenny" class="com.example.springidol.Instrumentalist">
  <property name="song" value="Jingle Bells" />
  <property name="instrument" ref="saxophone" />
</bean>

<!-- "p" namespace 이용 -->
<bean id="kenny" class="com.example.springidol.Instrumentalist"
  p:song="Jingle Bells" 값 전달
  p:instrument-ref="saxophone" />

 

생성자 방식 vs Setter 방식

  • 생성자 방식
    1. Bean 객체를 생성하는 시점에 모든 의존 객체 주입
    2. 성능상 유리
    3. NullPointerException 발생 가능성 낮음
    4. 생성자 인자들의 순서대로 적합한 의존 객체를 전달해야 함
  • Setter 방식
    1. 생성자를 통해 bean 객체가 생성된 후 의존 객체 주입
    2. 성능 다소 저하 (setter을 별도 실행하기 때문)
    3. NullPointerException 발생 가능 (setter 실행이 누락된 경우)
    4. setter method를 통해 각 필드마다 필요한 의존 객체를 주입하므로 설정이 명확하고 용이

 

Collection Wiring

collection type property 설정

  • Bean property가 Collection type인 경우(List, Set, Map..)
  • DI 설정시 collection 객체를 직접 정의하여 주입
  • Collection 정의를 위한 XML elements: <list>, <set>, <map>, <props>
    • 위 element들은 <property>의 자식으로 사용
  • Collection 원소 정의를 위한 elements: <ref>, <value> 등
    • 위 element들은 <list>, <set>, <map>, <props>의 자식으로 사용

Collection의 원소가 bean 객체인 경우

<bean id="springIdol" class="com.example.springidol.SpringIdol">
  <property name="performers">
    <list>
      <ref bean="duke"/>
      <ref bean="kenny"/> 
      <ref bean="hank"/>
    </list>
  </property>
</bean>

Collection의 원소가 Java 기본 타입인 경우

<bean id="springIdol" class="com.example.springidol.SpringIdol">
  <property name="scores">
    <list>
      <value>5.0</value>
      <value>4.5</value>
    </list>
  </property>
</bean>
  • Bean property가 generic type으로 선언된 경우 값들의 타입이 자동 변환
  • generic type이 아닌 경우 원소들은 String 타입

Map type 예시

<bean id="hank" class="com.example.springidol.OneManBand">
  <property name="instruments">
    <map>
      <entry>
        <key><value>HARMONIC</value></key> → 자식 엘리먼트 표현
        <ref bean="harmonica" />
      </entry>
      <entry key="GUITAR" value-ref="guitar" /> → 속성 표현
      <entry key="CYMBAL" value-ref="cymbal" />
    </map>
  </property> 
</bean>

Properties type 예시

<bean id="hank" class="com.example.springidol.OneManBand">
  <property name="instruments">
    <props>
      <prop key="GUITAR">STRUM STRUM STRUM</prop>
      <prop key="CYMBAL">CRASH CRASH CRASH</prop>
      <prop key="HARMONICA">HUM HUM HUM</prop>
    </props>
  </property>
</bean>
  • java.util.Properties는 key와 value가 모두 String인 Map과 같음

 

SpEL을 이용한 DI 설정

SpEL (Spring Expression Language)

  • 실행 시간에 평가되는 식 (expression)을 이용하여 값이나 객체를 bean의 property나 생성자의 인자로 전달하는 간결한 방법 제공
  • 형식: #{ }
  • 특징
    • ID를 통해 bean 참조 가능
    • Bean의 property를 접근하거나 method를 호출 가능
    • 산술, 관계, 논리 연산 지원
    • 정규식을 이용한 값 매칭
    • Collection 처리
<property name="count" value="#{5}"/> → int
<property name="message" value="The value is #{89.7}"/> → double in a string
<property name="name" value="#{'Chuck'}"/> → String (작은따옴표 이용)
<property name="enabled" value="#{false}"/>

<property name="instrument" value="#{piano}"/> → bean ID/name (주의: value 속성 사용)
<property name="song" value="#{kenny.song}"/> → song property in kenny bean
<property name="song" value="#{songSelector.selectSong()}"/> → method 호출
<property name="song" value="#{songSelector.selectSong().toUpperCase()}"/> 

<property name="multiplier" value="#{T(java.lang.Math).PI}"/> → Math 클래스의 PI 값 참조
<property name="randomNumber" value="#{T(java.lang.Math).random()}"/> 
→ Math 클래스의 random() 호출 (0~1 사이의 난수 값 반환)
  • 7행: song이 private이면 getter method를 호출 (getter가 존재해야 함)
  • 11~13행: T()는 클래스 이름을 인자로 지정

 

'프로그래밍 > Spring' 카테고리의 다른 글

[Spring] Auto-wiring  (0) 2022.04.25
[Spring] Spring MVC(2)  (0) 2022.04.22
[Spring] Spring MVC(1)  (0) 2022.04.17
[Spring] Spring DI  (0) 2022.04.01
복사했습니다!