1.2.3 빈 의존관계 설정 방법
빈 사이의 의존관계 메타 정보를 작성하는 방법은 여러 가지 기준으로 분류가 가능
- DI 할 대상을 선정하는 방법으로 분류할 경우
- 명시적으로 지정하는 방법 (DI 할 빈의 아이디를 직접 지정)
- 일정 규칙에 자동으로 선정하는 방법 (자동와이어링
autowiring
)
- 메타정보 작성 방법으로 분류할 경우
- XML <bean>, 스키마를 가진 전용태그, 어노테이션, 자바코드에 의한 직접적인 DI
- 빈 스캐너에 의한 빈 등록 방법과 어노테이션 방식은 둘다 비슷하지만 의존관계 주입에 사용되는 어노테이션은 빈 스캐너에 의해 등록될 때만 사용되는게 아니라는 점에서 차이가 발생
- 빈 등록 방식과 빈 의존관계 주입 방법은 메타정보 작성 방법이 항상 같지 않음을 주의
- Ex) <bean>태그를 사용해 빈을 등록하면서 의존관계 정보는 XML 태그 대신 어노테이션을 이용해 혼용사용이 가능, 자바 코드에 의한 빈 등록의 경우도 어노테이션과 혼용 가능
- 일반적으로 DI는 스프링이 관리하는 빈 오브젝트 사이의 관계를 말하지만 넓게 보면 빈 외의 오브젝트 또는 단순 값을 주입하는 것도 포함
XML: <property>, <constructor-arg>
<bean>을 이용해 등록했다면 프로퍼티와 생성자 두 가지 방식으로 DI 지정이 가능
- 프로퍼티는 자바빈 규약에 따르는 수정자 메소드를 사용
- 생성자는 빈 클래스의 생성자를 사용
<property>: 수정자 주입
- 수정자를 통해 의존관계의 빈을 주입하려면 <property> 태그를 사용, DI의 가장 대표적인 방법
- ref 애트리뷰트를 사용하면 빈 이름을 이용해 주입할 빈을 찾음
<bean ...> <property name="printer" ref="defaultPrinter" /> </bean>
- value 애트리뷰트는 단순 값 또는 빈이 아닌 오브젝트를 주입할때 사용
<property name="name" value="Spring" /> <property name="age" value="30" /> <property name="myClass" value="java.lang.String" />
- 스프링은 문자열로 작성된 value 값을 수정자 타입에 맞게 변환을 시도, 문제 없으면 값은 DI
- String과 int같은 경우 내장 변환기를 이용해 값을 변환
- myClass와 같이 Class 타입의 경우 문자열에 클래스 오브젝트로 변환
- property에 주입될 빈 또는 값의 타입이 호환이 되는지 확인 필요
<constructor-arg>: 생성자 주입
- 생성자를 통한 빈 또는 값의 주입에 사용, 생성자를 사용해서 한번에 여러개 오브젝트 주입 가능
- 각 파라미터마다 하나의 빈 또는 값을 지정
- 생성자 파라미터는 파라미터의 순서나 타입을 명시하는 방법이 필요
- 생성자 주입 예시
생성자 주입용 클래스
public class Hello { ... public Hello(String name, Printer printer) { this.name = name; this.printer = printer; } }
index 지정 방법
<bean id = "hello" class = "springbook.leaningtest.spring.ioc.bean.Hello"> <constructor-arg index="0" value="Spring" /> <constructor-arg index="1" ref="printer" /> </bean>
타입 지정 방법 (파라미터에 중복되는 타입이 없는 경우)
<constructor-arg type="java.lang.String" value="Spring" /> <coustructor-arg type="springbook.leaningtest.spring.ioc.bean.Printer" ref="printer" />
XML: 자동와이어링
- 자동와이어링 방식은 XML 문서의 양을 대폭 줄여줄 수 있는 획기적인 방법
- 하지만 그만큼 위험도 따르므로 주의가 필요
- 프로퍼티나 생성자 파라미터를 지정하지 않고 정해진 규칙으로 자동 DI 설정을 컨테이너가 추가
- 자동으로 관계가 맺어져야 할 빈을 찾아서 연결해준다는 의미로 자동와이어링
- 대표적으로 이름을 사용하는 자동와이어링과 타입을 사용하는 자동와이어링을 사용
byName: 빈 이름 자동와이어링
- 프로퍼티의 이름과 프로퍼티에 DI 할 빈의 이름이 비슷하거나 같은 경우가 많음
- 보통 빈의 이름은 클래스 이름이나 빈의 구현할 대표적 인터페이스 이름과 동일
- 프로퍼티 이름과 참조 빈 이름이 동일한 경우 예시
<bean id="hello" ...> <property name="printer" ref="printer" /> </bean> <bean id="printer" class="...StringPrinter">
StringPrinter
클래스는Printer
인터페이스를 구현한 클래스
- hello 빈의
printer 프로퍼티
도 같은Printer
인터페이스 타입으로 선언
- 프로퍼티의 이름을 인터페이스 이름을 따라 printer라고 일반적으로 정의
autowire
모드를 지정하면<property name="printer" .../>
생략 가능 (아래 예시)
- 이름을 이용한 자동와이어링 적용 예시
<bean id="hello" class="...Hello" autowire="byName"> <property name="name" value="Spring" /> </bean> <bean id="printer" class="...SpringPrinter" />
- printer 프로퍼티 선언은 생략했지만
<bean>
의autowire="byName"
에 의해 자동으로 등록
- Hello 클래스에는
setPrinter()
가 있고 이름이 같은printer
빈이 있어서 DI 한다고 판단
- printer 프로퍼티 선언은 생략했지만
- 이름을 이용한 자동와이어링은 빈의 모든 프로퍼티에 대해 이름이 동일한 빈을 찾아서 연결
- 프로퍼티와 이름이 같은 빈이 없는 경우 무시
- 자동와이어링을 적용하면서 name 프로퍼티처럼 명시적 선언도 함께 사용 가능
- 자동와이어링은 <bean>와 <beans> 애트리뷰트로 선언 가능 (<beans>는 모든빈 적용)
<beans default-autowire="byName"> <bean>...</bean> ... </beans>
- 이름에 의한 자동와이어링 방식을 사용하는 경우 대부분 디폴트 자동와이어링 옵션을 이용
- 자동와이어링이 어려운 프로퍼티 값이나 특별한 이름을 가진 프로퍼티는 명시적으로 선언
byType: 타입에 의한 자동와이어링
- 프로퍼티의 타입과 각 빈의 타입을 비교해서 자동으로 연결해주는 방법
- 이전에 만들어진 클래스를 재사용하거나 규모가 큰 프로젝트라 모든 개발자가 규칙에 따라 정확하게 이름 부여하기가 어려운 경우 이름 대신 타입에 의한 자동와이어링을 사용
- <bean>은
autowire="byType"
을 설정, <beans>는default-autowire="byType"
로 설정
- 타입에 의한 자동와이어링 예시
- Hello 클래스에는 printer라는 이름의 프로퍼티가 존재
- DI하고 싶은 빈의 이름은
mainPrinter
(이름 자동와이어링 연결 불가능 → 타입 사용)
<bean id="hello" class="...Hello" autowire="byType">...</bean> <bean id="mainPrinter" class="...StringPrinter" />
mainPrinter
빈은 Printer 인터페이스를 구현한StringPrinter
- Hello의 printer 프로퍼티
Printer
인터페이스 타입 (setPrinter(Printer printer)
)
- 이름은 다르지만 타입이 같은 경우 타입 자동와이어링을 통해 연결
- 타입에 의한 자동와이어링의 단점
- 타입이 같은 빈이 두 개 이상 존재하는 경우 적용 불가능 (스프링 결정 불가능)
- 이름에 의한 자동와이어링은 이름과 빈의 아이디만 비교하므로 상대적으로 빠름
- 빈의 모든 프로퍼티에 일괄 적용된다는 점도 단점
- 프로퍼티 개수가 많아지면 자동와이어링 대상이 아님에도 한 번씩 모든 빈의 타입과 비교하는 작업이 발생, 빈이 많아지고 프로퍼티가 늘어나면 적지 않은 시간 소요
- 생성자 파라미터를 이용하는 방법은 생성자에
autowire="constructor"
애트리뷰트 이용
- 자동와이어링은 XML 설정 파일의 양을 대폭 줄여줄 수 있는 획기적인 방법
- XML 안에서 자동와이어링을 사용하는 방식에 몇 가지 단점
- XML만 봐서는 빈 사이의 의존관계를 알기가 힘듬
- 프로퍼티 이름이나 타입을 가지고 컨테이너가 런타임시에 자동으로 의존관계를 생성 때문
- 빈 클래스 프로퍼티에 대응되는 빈이 존재해야만 DI가 발생 (항상 DI 되지 않음)
- 이름을 이용한 자동와이어링에선 오타로 DI 되지 않고 넘어갈 위험도 존재
- 타입에 의한 자동와이어링은 타입이 두 개 이상이면 문제가 발생
- 하나의 빈에 대해 한가지 자동와이어링 방식만 지정하는 방법도 한계점 (타입, 이름 같이 X)
- XML 문서 전용의 빈 등록 방식을 사용한다면 자동와이어링을 적극적으로 고려
- 명명 규칙과 적절한 설정을 해주면 XML의 양을 획기적으로 줄일 수 있어 관리하기 편리
- 기존의 빈의 새로운 의존관계가 추가될때 수정자 메소드만 추가해주면 되어 부담 최소화
- 빈 스캐닝 방식으로 등록된 빈은 XML로 <property>를 지정하거나 자동와이어링되게 못씀
XML: 네임스페이스와 전용 태그
- 스키마를 정의해서 사용하는 전용 태그의 의존관계 지정은 단순하지 않음
- 관례적으로 전용 태그에 의해 만들어지는 빈을 다른 빈이 참조할때 id를 사용해 빈 id를 지정
- 전용 태그를 참조하는 빈 예시
<oxm:jaxb2-marshaller id="unmarshaller" contextPath="..." /> <bean id="sqlService" class="springbook.user.sqlservice.oxmSqlService"> <property name="unmarshaller" ref="unmarshaller" /> <property name="sqlRegistry" ref="sqlRegistry" /> </bean>
- 전용 태그로 만들어지는 빈이 일반 <bean> 태그로 선언된 빈을 DI 할 수도 있음
- 스프링의 전용 태그는 -ref로 끝나는 애트리뷰트를 이용해 DI 할 빈을 지정하는 관례가 존재
- AOP에
pointcut
은 ref가 붙은 경우와 붙지 않는 경우에 분명한 차이가 존재하므로 주의 필요<aop:config> <aop:advisor advice-ref="transactionAdvice" pointcut="bean("Service)" /> </aop:config> <bean id="transactionAdvice" ...>
- 다수의 전용 태그는 아이디 조차 선언하지 않음, 내부적으로 빈이 만들어지지만 다른 빈과 DI로 연결되기 보다는 컨테이너가 참조하는 설정정보로만 사용하기 떄문
- 타입에 의한 자동와이어링과 같이 잘 파악하지 않는 방식은 지양, id로 명시적 선언이 바람직
애노테이션: @Resource
- XML 대신 애노테이션을 이용해 빈의 의존관계를 정의할 수 있는 2가지 방법이 존재
- @Resource는 <property> 선언과 비슷하게 주입할 빈을 아이디로 지정하는 방법
- @Resource는 수정자 메소드가 없어도 직접 내부 필드 DI가 가능
수정자 메소드
- 수정자는 가장 대표적인 DI 방법
public class Hello { private Printer printer; ... @Resource(name="printer") public void setPrinter(Printer printer) { this.printer = printer; } }
- name은 지정하지만 프로퍼티 이름은 안적어도 동작, 메소드 이름으르부터 프로퍼티 이름을 끌어 낼 수 있기 때문에 가능
- 이름이나 타입과 같은 소스코드의 메타정보를 활용 가능한 것이 애노테이션의 장점
- @Resource와 같은 애노테이션으로 된 의좐관계를 DI하려면 세가지 방법 중 하나를 선택
- XML의
<context:annotation-config />
- XML의
<context:component_scan />
AnnotationConfigApplicationContext
또는AnnotationConfigWebApplicationContext
- XML의
<context:annotation-config />
는 @Resource와 같은 어노테이션 의존관계 정보를 읽어 메타 정보를 추가해주는 기능을 가진 빈 후처리기를 등록해주는 태그
<context:component-scan />
빈 스캐닝을 통한 빈 등록 방법을 지정, 내부적으로 첫 번째 태그로 만들어지는 빈을 함께 등록
- 세번째 방법은 빈 스캐너와 애노테이션 의존관계를 읽는 애플리케이션 컨텍스트를 사용
- @Resource 의존관계 정의 방법을 이용하는 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 xmlns:context="http://www.springframework.org/chema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config /> <bean id="hello" class="springbook.learningtest.spring.ioc.annotation.Hello"> <property name="name" value="Spring" /> </bean> <bean id="printer" class="springbook.learningtest.spring.ioc.annotation.StringPrinter" /> </beans>
- XML 안에서 빈 스캐닝을 이용하는 경우에는
<context:component-scan>
태그만 사용하면 가능 빈 등록도 자동으로 이뤄지기 때문에 <bean>은 모두 제거 가능 대신 Hello와 StringPrinter 클래스에@Component
를 붙여주는 작업 필요<context:component-scan base-package="...ioc.annotation" />
- 빈 스캐닝은 항상 애노테이션 의존관계 설정을 지원한다고 기억
필드
- @Resource는 필드에도 붙이는것이 가능 (public 아니어도 가능)
@Component public class Hello { @Resource(name="printer") private Printer printer; // setPrinter() 메소드 없음 }
- 스프링에서 필드에 바로 DI 해주는 방법을 필드 주입이라고 부름
- 테스트처럼 컨테이너 밖에서 수동 DI할 떄는 불편, 단위 테스트가 필요한 클래스는 수정자 필요
- 컨테이너를 이용하는 통합 테스트를 주로 하는 DAO에서는 필드 주입이 가능하므로 문제 없음
- @Resource의 대표적인 적용 예는 DAO에 DataSource를 DI 하는 경우
public class UserDao { @Resource DataSource dataSource; ... }
- 필드에 @Resource를 붙이는 것이 수정자에 붙이는 것 보다 DI 구조 파악이 쉬움
- @Resource는 자동와이어링처럼 참조하는 빈의 이름 생량도 가능
@Resource private Printer printer;
@Resource와 XML의 이름을 이용한 자동와이어링의 차이점
- XML의 자동와이어링
- 프로퍼티에 주입할 만한 후보 빈이 없을 경우 무시 (에러 발생 X)
- DI 가능한 것만 찾아내서 주입해주는 느슨한 방법
- @Resource
- 반드시 참조할 빈이 존재해야하며 없는 경우 예외가 발생
- DI 적용 여부를 프로퍼티마다 세밀하게 제어가 가능
- 기본적으로 참조할 빈의 이름을 이용해서 빈을 찾음
- 이름으로 참조할 빈이 없는경우 타입으로도 다시 한번 빈을 찾음 (타입 찾기는 권장X)
애노테이션: @Autowired/@Inject
- 애노테이션을 이용한 의존관계의 두번째 방법은 @Autowired와 @Inject를 이용하는 방법
- 기본적으로 타입에 의한 자동와이어링 방식으로 동작, 의마나 사용법은 거의 동일
@Autowired
는 XML에 타입 자동와이어링 방식을 생성자, 필드 수정자 메소드, 일반 메소드의 네가지로 확장한 방법
수정자 메소드와 필드
- 필드와 수정자 메소드는 @Resource와 사용 방법이 비슷
- @Resource와 다른 점은 이름 대신 필드나 프로퍼티 타입을 이용해 후보 빈을 찾음
- XML의 타입 자동와이어링과 비슷하며 그래서 자동와이어링을 뜻하는
@Autowired
라고 부름public class Hello { @Autowired private Pritner printer;
public class Hello { private Printer printer; @Autowired public void setPrinter(Pritner printer) { this.printer = printer; }
생성자
- @Autowired는 @Resource와 다르게 생성자 부여도 가능
- 생성자의 모든 파라미터 타입에 의한 자동와이어링이 적용
public class BasSqlService implements SqlService { protected SqlReader sqlReader; protected SqlRegistry sqlRegistry; @Autowired // 한 개의 생성자에만 부여 가능 public BasSqlService(SqlReader sqlREader, SqlRegistry sqlRegistry) { this.sqlReader = sqlReader; this.sqlRegistry = sqlRegistry; } ...
- 단 하나의 생성자에만 사용할 수 있다는 제한이 존재
일반 메소드
- XMl을 이용한 의존관계 설정에서는 가능하지 않은 애노테이션 방식의 고유한 기능
- 생성자 주입과 수정자 메소드 주입은 각기 장단점이 존재
- 그래서 등장한 것이 일반 메소드를 사용하는 DI 방법
- 파라미터를 가진 메소드를 만들고 @Autowired를 붙여주면 각 파라미터 타입 기준으로 자동와이어링을 해서 DI가 가능
- 한 번에 여러 개의 오브젝트 DI가 가능, 코드도 상대적으로 깔끔하게 처리 가능
- 단, 이렇게 만들어진 클래스는 XML을 통해서는 의존관계를 설정할 방법이 없음을 주의
public class BadSqlService implements SqlSErvice { protected SqlReader sqlReader; protected SqlRegistry sqlRegistry; @Autowired // 한 개 이상의 설정용 메소드에 부여 가능 public void config(SqlReader sqlReader, SqlRegistry sqlRegistry) { this.sqlReader = sqlReader; this.sqlRegistry = sqlRegistry; }
컬렉션과 배열
- @Autowired를 이용하면 같은 타입의 빈이 하나 이상 존재할 때 모두 받는것이 가능
- 대상이 되는 필드나 프로퍼티, 메소드의 파라미터를 컬렉션이나 배열로 선언
@Autowired Collection<Printer> printers; //Set, List도 가능 @Autowired Printer[] printers; @Autowired Map<String, Printer> printerMap; //String으론 빈 아이디, Printer은 타입의 빈 값
- 컬렉션과 배열은 충돌을 피하려는 목적으로 사용하면 안됌
- 타입이 같은 빈 모두를 참조하거나 그중에서 선별적으로 필요한 빈을 찾을때 사용을 권장
- DI 할 빈의 타입이 컬렉션인 경우 @Autowired로 자동 설정이 불가능
- 빈 자체가 컬렉션인 경우 @Resource를 이용
Qualifier
- Qualifier는 타입 외의 정보를 추가해서 자동와이어링을 세밀하게 제어하는 보조적인 방법
DataSource
타입의 빈이 하나 이상 등록된 경우 (2개 DB 사용 예시)<bean id="oracleDataSource" class="...XxxDataSource" > ... </bean> <bean id="mysqlDataSource" class="...YyyDataSource" > ... </bean>
- 두 개의 빈이 모두 DataSource 타입이 문제, @Resource를 이용해 이름을 지정하면 문제 X
@Resource("oracleDataSource") DataSource dataSource;
- @Autowired를 사용하면 에러가 발생. 같은 타입의 빈이 2개 발견됐고 DI 해줄 판단이 없기 떄문
- @Qualifier라는 빈 선정을 도와주는 부가 정보를 이용하면 해결 가능
@Autowired @Qualifier("mainDB") DataSource dataSource;
<bean id="oracleDataSource" class="...XxxDataSource"> <qualifier value="mainDB" /> </bean>
- XML이 아닌 @Component를 이용해 자동등록하는 경우 @Qualifier를 부여
@Component @Qualifier("mainDB") public class OracleDataSource {
- @Qualifier는 빈에 부가적인 속성을 지정해주는 효과
- 값을 넣는 수준이 아니라, 좀 더 의미 있는 애노테이션을 만드는 것도 추천
//커스텀 한정자 애노테이션 @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Database { String value(); }
//main에 해당하는 DB를 연결하는 DataSource 타입의 빈 지정 @Autowired @Database("main") DataSource dataSource; //문자로된 엘리먼트 없어 더 단순한 한정자 @Autowired @MainDB DataSource dataSource;
- 추가적인 기능은
@Qulifier("mainDB")나 <qualifier value="mainDB" />
를 가진 빈이 없는 경우, 마지막으로 mainDB라는 이름의 빈이 있는지 한번 더 확인하고 있다면 DI 가능
- 이름에 의한 빈 선택도 가능하다는 의미지만 권장하진 않음 (@Resource 사용을 권장)
- @Qualifier는 부여 대상이 필드와 수정자, 파라미터 (생성자 일반 메소드 사용 못함)
- 파라미터에 @Qualfier를 직접 붙이면 사용이 가능
@Autowired public void config(@Qualifier("mainDB") DataSource dataSource, Printer printer) {
- @Autowired는 DI할 후보 빈이 반드시 필요. 없는 경우 에러가 발생
- 프로퍼티의 DI를 선택적으로 가능하게 하려면 @Autowired의 reuqired를 false로 선언
@Autowired(requried=false) Printer printer;
@javax.inject.Inject
- 필드, 생성자, 일반메소드를 사용해 자동와이어링 선언한다는 점은 @Autowired와 유사
- @Autowired의 required 엘리먼트에 해당하는 기능은 제공 안함
@javax.inject.Qualifier
- JSR-330의 @Qualifier는 스프링의 @Qualifier와 이름이 같지만 패키지와 사용방법은 다름
- 스프링의 @Qualifier는 스트링 값을 가질 수 있고 자체로 @Autowired와 함께 사용이 가능
- JSR-330의 @Qualifier는 한정자로 사용해서 @Inject와 함꼐 못 씀, 다른 한정자 애노테이션을 정의하는 용도로만 사용 가능
- JSR-330의 @Inject와 @Qualifier는 스프링 외의 표준 JavaEE 6 환경에서도 같은 의미로 사용 가능
- 기능이 제한적이고 단순하기 떄문에 독립적인 DI 설정을 가진 클래스가 아니라면 스프링의 @Autowired와 @Qualifier를 사용하는 편이 좋음
@Autowired와 getBean(), 스프링 테스트
- 애플리케이션 컨텍스트에서 빈을 가져올때 getBean("빈이름") 메소드를 사용, getBean()은 기본적으로 Object 타입을 리턴하므로 캐시팅이 필요. 제네릭 메소드를 이용한 방법을 선호
Printer printer = ac.getBean("myprinter", Printer.class);
- 특정 타입의 빈이 하나만 존재한다면 @Autowired와 같이 타입을 이용해 빈을 찾는게 가능
Printer printer = ac.getBean(Printer.class);
- 같은 타입의 빈이 두 개 이상이면 에러가 발생, @Qualifier를 사용 못하므로 이름을 사용
자바 코드에 의한 의존관계 설정
- @Configuration과 @Bean을 이용해 자바 코드로 빈을 등록하는 경우 설정하는 방법 3가지
애노테이션에 의한 설정 @Autowired, @Resource
- 빈은 자바 코드에 의해 생성되지만 의존관계는 빈 클래스의 애노테이션을 이용해서 관계를 설정
public class Hello { @Autowired Printer printer;
- Hello 클래스를 자바 코드를 이용해 빈으로 등록하더라도 printer DI 설정은 코드 외의 방법으로 사용이 가능
@Configuration public class Config { @Bean public Hello hello() { return new Hello(); } @Bean public Printer printer() { return new Printer(); }
- 빈으로 등록하면 의존관계는 애노테이션 의존관계 설정용 후처리기에서 별도로 설정
- @Autowired 등을 사용했더라도 일부 프로퍼티는 코드에 직접 의존관계 지정이 가능
@Bean 메소드 호출
- @Configuration과 @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(); } }
- 자바 코드로 DI하는 가장 직관적인 방법 하지만 자바 코드로 이해하면 오해하기가 쉬움
- 스프링이
@Configuration
이 붙은 클래스를 조작해 한 개의 오브젝트를 호출 (매번 객체생성 X)
- 다른 빈에서
printer()
를 여러번 사용한다고 해도 싱글톤이기 떄문에 더이상 오브젝트 생성X
@Bean과 메소드 자동와이어링
- 두 번째 방법의 단점을 극복하기 위해서 사용이 가능
- @Bean이 붙은 메소드를 호출하는 대신 그 빈의 래퍼런스를 파라미터로 주입받는 방식을 사용
- 빈에 적용되는 DI가 아니라 빈 설정정보로서의 메소드에 적용되는 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; }
@Configuration
이 붙은 Config 클래스도 하나의 빈이고@Bean
이@Autowired
를 포함하고 있다고 생각
- 이 방식의 장점은 메소드 호출이 아닌 파라미터로 받기 때문에 자바 코드가 자연스러워짐
@Autowired
와 마찬가지로@Qualifier
를 파라미터에 추가해도 사용이 가능
- 이렇게 제공되는 빈은
@Configuration
이 붙은 클래스뿐만 아니라 XML이나 빈 스캐너를 이용해서 등록되는 빈을 가져와서 사용이 가능
빈 의존관계 설정 전략
- 빈 등록 방법과 의존관계 설정방법은 다양하므로 가능한 빈 설정 메타정보를 일찍하여 가이드라인을 잘 만든는 것이 중요
- 개발자 별로 제멋대로 방식을 사용하면 나중에 코드 관리가 어려워지는 현상 발생
XML 단독
- 빈 등록과 의존관계 설정까지 모두 XMl만으로 구성하는 방법
- 컨테이너 설정과 네임스페이스와 전용 태그의 사용은 필수, 빈 등록은
<bean>
사용
- 한가지 선택 사항은 XML 자동와이어링을 적용할지, 의존관계 정보를 직접
<property>
나<constructor-arg>
정의할지에 대한 결정이 필요
- 가능한 한 XML 자동와이어링 선택을 추천 그렇지 않으면 애플리케이션의 규모가 커지고 빈의 개수가 많아지면 XML 관리가 매우 어려움
- XML 자동와이어링은 가능한 한 이름에 의한 방식을 사용하는 것을 추천
타입에 의한 자동와이어링 방법은
@Autowired
의 세밀한 방식과는 달리 불편하고 느림@Qualifier
처럼 타입 중복이 발생할 때 특정 빈에 우선권 부여가 가능하지만 불편
XML과 애노테이션 설정의 혼합
- 빈은 XMl로 등록하지만 의존관계 정보는
@Autowired
나@Resource
를 자주 사용
- 빈 스캐너로 자동등록할 경우 대상 파악이 어려운 경우 <bean> 태그를 이용한 빈 등록을 선호할 수 있지만 <property>를 일일이 선언해서 의존관계를 설정하는건 어려운 작업
- XML의 일괄적인 자동와이어링이 불편하면 의존관계 설정은 애노테이션 제어를 추천
애노테이션 단독
- 빈의 등록도
@Component
애노테이션을 이용해 스캐너에 맡기고 의존관계도@Autowired
를 사용하는 방법
- XML이 필요 없기 때문에 생산성이 높고 수정이 편리하다는 장점이 있어 비중이 늘어나는 방식
- 일부 기술 서비스 빈이나 컨테이너 설정용 빈은 XML을 이용 가능
- 스키마와 전용 태그를 사용하기 떄문에 얻을 수 있는 장점이 많기 때문
- XML 없이 순수한 애노테이션만의 설정을 원한다면
@Configuration
자바 코드를 이용해 등록
'개발서적 > 토비 스프링 3.1-Vol.2' 카테고리의 다른 글
[토비의 스프링 - Vol.2] 1장 - 1.4 기타 빈 설정 메타정보 (0) | 2022.01.17 |
---|---|
[토비의 스프링 - Vol.2] 1장 - 1.3 프로토타입과 스코프 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.2.5 컨테이너가 자동등록하는 빈 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.2.4 프로퍼티 값 설정 방법 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.2.2 빈 등록 방법 (0) | 2021.07.06 |