Spring Container
핵심 기능
- 자바 객체(bean)의 라이프 사이클 관리
- Dependency Injection(DI)
종류
- BeanFactory interface의 구현체
- Bean 객체를 생성하고 DI를 실행하는 기본적인 기능 제공
- 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 식별자" />
- <constructor-arg>를 사용하여 생성자의 인자(argument) 지정
더보기
값의 타입 설정
- <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 선언
- xmlns:c="http://www.springframework.org/schema/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 식별자" />
- <property>를 사용하여 값이나 의존 객체 지정
- 효과
- 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" />
- 네임스페이스 접두사 p 선언
- xmlns:p="http://www.springframework.org/schema/p"
생성자 방식 vs Setter 방식
- 생성자 방식
- Bean 객체를 생성하는 시점에 모든 의존 객체 주입
- 성능상 유리
- NullPointerException 발생 가능성 낮음
- 생성자 인자들의 순서대로 적합한 의존 객체를 전달해야 함
- Setter 방식
- 생성자를 통해 bean 객체가 생성된 후 의존 객체 주입
- 성능 다소 저하 (setter을 별도 실행하기 때문)
- NullPointerException 발생 가능 (setter 실행이 누락된 경우)
- 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 |