CS 공부 17일차. 오늘은 Spring의 중요 개념 중 하나인 DI가 실제로 어떻게 적용되는지를 위주로 토비의 스프링 3.1을 읽고 내용을 정리해 보았습니다.
<context : annotation-config/>
<context : component-scan/>
annotation-config로 만들어지는 빈을 함께 등록해주며, 빈 스캐닝을 통한 빈 등록방법을 지정하는 전용 태그
AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext : 빈 스캐너와 애노테이션 의존관계 정보를 읽는 후처리기를 내장한 ApplicationContext
Bean 등록방법과 Bean 의존관계 설정 방법은 같지 않아도 된다.
DI할 Bean의 id 직접 지정
Autowiring : 명시적으로 프로퍼티나 생성자 파라미터를 지정하지 않고 미리 정해진 규칙을 이용해 자동으로 DI 설정을 Container가 추가하도록 만드는 것이다.
<bean>
<property name=“sample” ref=“sample” />
<property name=“age” value=“30” />
</bean>
<constructor-arg type=“java.lang.String” value=“Spring” />
<constructor-arg type=“springbook.learningtest.spring.ioc.bean.Printer” ref=“printer” />
<bean id=“hello” class=“springbook.learningtest.spring.ioc.bean.Hello" autowire=“byName">
//<property name=“sample” ref=“sample” />는 자동으로 추가됨
<property name=“age” value=“30” />
</bean>
<beans default-autowire=“byName”>
<bean>...</bean>
...
</beans>
byName autowire
수정자(setter) 메소드
@Resource(name=“sample”)
public void setSample(Sample sample){
this.sample=sample;
}
@Resource(name=“sample”)
private Sample sample;
필드 주입이라고 한다.
setter를 만들면 단위테스트에 편리하고 통합테스트에는 setter없이 필드주입만 사용해도 괜찮다.(ex : DAO에 DataSource를 DI하는 경우)
필드와 setter모두 name 생략 가능
XML의 Autowiring과 @Resource는 XML은 해당하는 빈이 없으면 무시하고 넘어가지만 @Resource는 예외를 발생시키는 차이점이 있다.
byType autowire
@Autowired는 스프링 전용이며 이와 유사한 @Inject는 다른 Java 프레임워크에서도 사용 가능
@Autowired는 XML byType Autowired를 생성자, 필드, 수정자 메소드, 일반 메소드로 확장한 것이다.
가장 유연하면서 강력한 기능을 가진 DI 설정 방법
테스트 클래스의 Object에 @을 이용한 의존관계 설정을 해준다.
필드
@Autowired
private ClassService classService;
@Resource와 다른 점은 이름 대신 필드나 프로퍼티 타입을 이용해 후보 빈을 찾는 다는 것이다.
수정자 메소드
@Autowired
public ClassController(ClassService classService) {
this.classService=classService;
}
@Autowired
Collection<ClassService> classService;
타입 외의 정보를 추가해서 자동와이어링을 세밀하게 제어할 수 있는 보조적인 방법
두가지 DB를 사용하는 경우에 두 빈이 모두 DataSource이므로 오류가 나면 아래와 같이 해결한다.
필드, 수정자 메소드, 파라미터에 부여할 수 있으며 생성자와 일반 메소드에 부여하는 것은 의미가 없다.
@Autowired
@Qualifier(“mainDB”)
DataSource dataSource;
<bean id=“oracleDataSource” class=“aDataSource">
<qualifier value=“mainDB”/>
</bean>
@Autowired
@mainDB
public class OracleDataSource{
...
}
메소드로 정의된 다른 빈을 메소드 호출을 통해 참조
@Configuration + @Bean로 빈을 생성했을 경우 DI 설정
@Autowired/@Resource
public class Hello{
@Autowired Printer printer;
}
@Configuration
public class Config{
@Bean public Hello hello(){
return new Hello();
}
@Bean public Printer printer(){
return new Printer();
}
}
//@Autowired가 후처리기로 진행되기 때문에 config에는 bean만 등록해주어도 된다.
@Configuration
public class Config {
@Bean public Hello hello(){
Hello hello = new Hello();
hello.setPrinter(printer());
return hello;
}
@Bean public Printer printer(){
return new Printer();
}
//직관적. 싱글톤으로 printer가 만들어짐. printer메소드를 직접 실행시켜 DI
@Configuration
public class Config {
@Bean public Hello hello(Printer printer){
Hello hello = new Hello();
hello.setPrinter(printer);
return hello;
}
@Bean public Printer printer(){
return new Printer();
}
//printer()에 의해 Printer 빈이 선언되었으며 이를 파라미터로 지정하여 DI
<bean id=“hello”>
<property name=“name” value=“Everyone” />
</bean>
<aop:advisor advice-ref=“ref” pointcut=“bean(*Service)” />
@Value(“{database.username}”)
private String username;
@Bean
public Hello hello(){
Hello hello = new Hello();
hello.setName(this.name);
return hello;
}
//런타임 시에 외부로부터 주입을 통한 초기화가 존재.
PropertyEditor : 자바에서 제공하는 타입 변환기로 기본타입, 오브젝트 타입, 배열등을 변환해준다.
ConversionService : Spring에서 제공하는 타입 변환기로 멀티 레드 환경에서 공유해 사용할 수 있으며 propertyEditor보다 작성이 간편하다.
<property name=“names”>
<list>
<value>Spring</value>
<value>IoC</value>
<value>DI</value>
</list>
</property>
<property name=“ages”>
<map>
<entry key=“Kim” value=“30” />
<entry key=“Lee” value=“25” />
<entry key=“Park” value=“20” />
</map>
</property>
<property name=“ages”>
<props>
<prop key=“id”>Spring</prop>
<prop key=“pw”>Book</prop>
</props>
</property>
XML에서 일부 설정정보(ex: dataSource)를 파일로 분리하여 프로퍼티 값으로 지정
로컬과 호스팅같이 서버환경이 다를때 다르게 적용해야하는 정보를 분리
@Vaule나 value attribute가 프로퍼티 파일을 참조하게 하면 효과적이다.
<context:property-placeholder location=“class path:database.properties” />
<property name =“username” value=${db.username} />
@Value(“${db.username}”)
String username;
<bean id=“user”>
<property name = “name” value=“Spring">
</bean>
<bean id=“names">
<property name =“username” value=“#{user.name}" />
</bean>
@Component(“user”)
public class User{
private String name=“Spring”;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
}
@Value(“#{user.name}”)
private String username;