Chapter2. 빈 와이어링(묶기)
2.1 스프링 설정 옵션 알아보기
- XML에서의 명시적 설정
- 자바에서의 명시적 설정
- 내재되어 있는 빈을 찾아 자동으로 와이어링 하기
2.2 자동으로 Bean 와이어링하기
- 컴포넌트 스캐닝 : @Component, @ComponentScan
- 오토 와이어링 : @Autowired
2.2.1 발견 가능한 빈 만들기
@Component
public class SgtPeppers implements CompactDisc {
...
}
@Configuration
@ComponentScan
public class CDPlayerConfig {
...
}
2.2.2 컴포넌트 스캔된 빈 명명하기
@Component("beanName") //Spring 종속적인 어노테이션
or
@Named("beanName") //JSR-330의 어노테이션이며 Spring의 @Component, @Qualifier와 동일하다.
- 참고 : @Component는 어떤 스프링이 관리하는 컴포넌트를 나타내는 일반적인 스테레오 타입이다. 좀더 세부적인 유스 케이들을 위하여 @Component의 구체화된 형태로 @Repository, @Service, @Controller들이 있다.
- @Repository : 퍼시스턴스(persistence) 레이어, 영속성을 가지는 속성(파일, 데이터베이스 등)
- @Service : 서비스 레이어 (비즈니스 레이어)
- @Controller : spring mvc 기반의 프리젠테이션 레이어
2.2.3 컴포넌트 스캐닝을 위한 베이스 패키지 셋팅
@ComponentScan("com.kakao.game.helloworld.service")
or
@ComponentScan(basePackages = "com.kakao.game.helloworld.service")
or
@ComponentScan(basePackages = {"com.kakao.game.helloworld.service", "com.kakao.game.helloworld.support"})
or
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})
2.2.4 오토와이어링 되는 빈의 에너테이션
- 생성자 주입
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
- property setter method
@Autowird
public void setCompactDisc(CompactDisc cd) {
this.cd = cd;
}
- 일반 method
- @Autowired 과 @Inject 및 @Resource 비슷하지만 차이가 있음.
- @Autowired : spring 전용, 타입에 맞춰 연결
- @Inject :java(JSR)에서 지원, 타입에 맞춰 연결
- @Resource : java(JSR)에서 지원, 이름으로 연결
@Autowired
private Chicken penguin; //Chicken 타입으로 연결됩니다.
@Inject
private Penguin chicken; //Penguin 타입으로 연결됩니다.
@Resource
private Chicken penguin; //penguin 타입으로 연결됩니다만, Chicken 클래스를 자료형으로 두었기에 캐스팅이 되지 않아 에러가 납니다
@Resource
private Bird penguin; //penguin 타입으로 연결되어 호출해보면 penguin 클래스의 값을 호출하는 것을 볼 수 있습니다.
@Autowired
@Qualifier("chicken")
pirvate Brid penguin; //타입이나 이름에 상관없이 chicken타입으로 연결
2.2.5 자동 설정 검증하기
2.3 자바로 Bean 와이어링하기
2.3.1 설정 클래스 생성 : @Configuration
@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class,SgtPeppers.class})
public class CDPlayerConfig {
}
2.3.2 간단한 Bean 선언하기 : @Bean
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc compactDisc() {
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
2.3.3 JavaConfig 주입
- 스프링의 모든 빈은 싱글톤으로 생성되므로, 서로 다른 빈에서 같은 인스턴스를 참조할 수 있다.
@Bean
public CDPlayer cdPlayer1() {
return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer cdPlayer2() {
return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer cdPlayer3(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
@Bean
public CDPlayer cdPlayer4(CompactDisc compactDisc) {
CDPlayer cdPlayer = new CDPlayer();
cdPlayer.setCompactDisc(compactDisc);
return cdPlayer;
}
2.4 빈을 XML로 와이어링하기
XML을 단독으로 사용할 때 특징
- 생성되는 모든 빈을 XML에서 확인 가능하다.
- 설정 정보를 코드로부터 분리할 수 있다.
- 스프링이 제공하는 모든 종류의 빈 설정 메타정보 항목을 지정할 수 있는 유일한 방법이다.
- 빈의 개수가 많아지면 관리하기 어렵다.
예제
1. XML 설정 생성하기
<?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">
</beans>
2. 빈 등록하기
<bean id="compactDisc" class="soundsystem.SgtPeppers" />
3. 생성자 주입하기
- 추후에 argument의 이름이 바뀔 수 있으니 주의해야 한다.
1) constructor-arg
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc" /> // 빈
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" /> // 리터럴
<constructor-arg> // 빈 컬렉션
<list>
<ref bean="sgtPeppers" />
<ref bean="whiteAlbum" />
<ref bean="hardDaysNight" />
...
</list>
</constructor-arg>
<constructor-arg> // 리터럴 컬렉션
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
...
</list>
</constructor-arg>
<constructor-arg index="0" ref="compactDisc" /> // 순서
<constructor-arg type="sountsystem.CompactDisc" ref="compactDisc" /> // 타입
<constructor-arg name="compactDisc" ref="compactDisc" /> // 이름
</bean>
2) c-namespace
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="compactDisc" /> // 이름으로 와이어링
<bean id="compactDisc"
class="soundsystem.BlankDisc"
c:_title="Sgt. Pepper's Lonely Hearts Club Band"
c:_artist="The Beatles" />
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_0-ref="compactDisc" /> // 순서로 와이어링
<bean id="compactDisc"
class="soundsystem.BlankDisc"
c:_0="Sgt. Pepper's Lonely Hearts Club Band"
c:_1="The Beatles" />
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_-ref="compactDisc" /> // 하나만 있을 때
<bean id="compactDisc"
class="soundsystem.BlankDisc"
c:_="Sgt. Pepper's Lonely Hearts Club Band" />
4. 프로퍼티 주입하기
1) property
<bean id="cdPlayer" class="soundsystem.properties.CDPlayer">
<property name="compactDisc" ref="compactDisc" />
<property name="title" value="Sgt. Pepper's Lonely Hearts Club Band" />
<property name="artist" value="The Beatles" />
<property name="tracks">
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
...
</list>
</property>
</bean>
2) p-namespace
<bean id="cdPlayer" class="soundsystem.properties.CDPlayer"
p:compactDisc-ref="compactDisc" />
<bean id="compactDisc" class="sound system.BlankDisc">
<p:title="Sgt. Pepper's Lonely Hearts Club Band" />
<p:artist="The Beatles" />
</bean>
<util:list id="trackList">
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
...
</util:list>
<bean id="compactDisc"
class="soundsystem.properties.BlankDisc"
p:title="Sgt. Pepper's Lonely Hearts Club Band"
p:artist="The Beatles"
p:tracks-ref="trackList" />
5. 자동 와이어링
다음과 같은 클래스가 있다고 하자.
public class Hello {
...
public Hello(String name, Printer printer) {
this.name = name;
this.printer = printer;
}
}
1) 이름으로 자동 와이어링
<bean id="printer" class="...StringPrinter" />
<bean id="hello" class="...Hello" autowire="byName"> //
<property name="name" value="Spring" />
// <property name="printer" ref="printer" />가 생략되었다. 빈의 이름과 프로퍼티의 이름이 같기 때문에 자동와이어링이 된다.
</bean>
- 오타 조심
2) 타입으로 자동 와이어링
<bean id="mainPrinter" class="...StringPrinter" />
<bean id="hello" class="...Hello" autowire="byType">
<property name="name" value="Spring" />
// <property name="printer" ref="printer" />가 생략되었다. 빈의 타입과 프로퍼티의 타입이 같기 때문에 자동와이어링이 된다.
</bean>
- 타입이 같은 빈이 두 개 이상 존재하면 쓸 수 없다.
- 타입 비교가 이름 비교보다 느리다.
3) 여러 빈을 자동 와이어링
<beans default-autowire="byName"> // 이 아래 모든 빈은 이름으로 자동 와이어링된다.
<bean>...</bean>
...
</beans>
생성자 주입 vs 프로퍼티 주입
- 프로퍼티 주입을 더 많이 쓰는 이유
- 역사적인 이유 - 초창기에 프로퍼티 주입에 좀 더 집중된 구조 - 때문에
- 프로퍼티 주입으로 더 많은 설정이 가능하기 때문에
- 유효한 객체를 만들기 위해서는 생성자 주입을 더 신경써주어야 한다.
2.5 설정 가져오기와 믹싱하기
1) JavaConfig끼리 참조하기
@Import({CDConfig.class, CDPlayerConfig.class})
2) XML끼리 참조하기
<import resource="cd-config.xml" />
3) JavaConfig로 XML 설정 참조하기
@ImportResource("classpath:cd-config.xml")
4) XML 설정에서 JavaConfig 참조하기
<bean class="soundsystem.CDConfig" />