티스토리 뷰
XML에서 빈을 등록했다면 생성자나 자바빈 규약에 따른 수정자(set으로 시작하는 메서드)에 의존관계 빈이나 값을 주입할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 | public class InjectionTest { public InjectionTest(String name, int age, String s) { System.out.println(name + "======" + age + "=========" + s.toString()); } public void setParameterSetting(String a) { System.out.println(a); } } | cs |
1 2 3 4 5 6 7 8 9 | <bean class="dev.wedding.kr.test.InjectionTest"> <!-- 생성자에 값 주입 --> <constructor-arg index="0" value="StringValue" /> <constructor-arg index="1" value="2016" /> <constructor-arg index="2" value="java.lang.String" /> <!-- set메서드(수정자)에 값을 주입 --> <property name="parameterSetting" value="choonie" /> </bean> | cs |
스프링 컨텍스트 XML설정 파일에서 InjectionTest빈을 등록하고 있으며, 그 안에 생성자와 수정자 메서드가 필요로 하는 파라미터(매개변수)를 설정하고 있다.
우선 <constructor-arg>는 생성자의 매개변수에 객체나 값을 주입하는 것이다.
index속성은 생성자의 매개변수 수가 여러개일 때 설정하는 것으로 0부터 시작한다. value속성에는 값을 넣는다. 값이 기본값이 아닌 객체라면 value대신 ref를 써서 등록된 빈의 이름을 지정하면 된다.
<property>는 수정자 메서드 매개변수에 들어갈 값을 설정하는 것이다.
name은 수정자 메서드 이름에서 set을 제외하고 첫글자를 소문자로 변경해야 한다.
역시 값은 value, 빈 참조는 ref속성을 사용한다.
1 2 3 4 5 | <bean class="dev.wedding.kr.test.InjectionTest2"> <constructor-arg type="java.lang.String" value="StringValue" /> <constructor-arg type="dev.wedding.kr.model.CarInfoProvider" ref="kiaCar" /> </bean> | cs |
생성자 각각의 파라미터에 중복되는 타입이 없다면 위와 같이 type속성 을 사용할 수 있다.
애노테이션을 이용해 빈의 의존관계를 정의할 수 있는 방법도 있다.
1 2 3 4 5 6 7 8 9 10 11 12 | @Component public class InjectionTest { private ConfigurationBeanFactory factory; @Resource(name = "configurationBeanFactory") public void setParameterSetting(ConfigurationBeanFactory factory) { this.factory = factory; CarInfoProvider cip = this.factory.kiaCar(); cip.getPrintCarInfo(); } } | cs |
@Resource를 사용함으로써 메서드의 매개변수에 의존관계 빈을 주입할 수 있다.
@Resource(name = "configurationBeanFactory")는 <property>에 대응 된다고 볼 수 있으며, XML에서 수정자 의존 주입을 설정할 때의 <property name="configurationBeanFactory" ref="configurationBeanFactory">와 같은 의미를 가진다.
그런데 이 같은 애노테이션들을 사용하기 위해서는 다음과 같은 방법중 하나를 사용해야 한다.
- 스프링 컨텍스트 XML파일에 <context:annotation-config /> 등록하여 DI
<context:annotation-config />는 @Resource와 같은 애노테이션의 메타정보를 추가해주는 빈 후처리기를 등록해주는 전용 태그다. 쉽게 말하면 @Resource가 본연의 기능을 할 수 있도록 지원하는 것일 뿐 빈을 등록해 주지 않는다.
그래서 따로 <context:annotation-config />와 함께 필요한 빈을 등록해줘야 한다.
1 2 3 4 5 6 7 | <context:annotation-config /> <bean id="configurationBeanFactory" class="dev.wedding.kr.test.ConfigurationBeanFactory"> </bean> <bean class="dev.wedding.kr.test.InjectionTest"> </bean> | cs |
- 스프링 컨텍스트 XML파일에 <context:component-scan /> 등록하여 DI
1 | <context:component-scan base-package="dev.wedding.kr.test" /> | cs |
<context:component-scan>만 사용하면 빈 스캐닝을 하고 빈 등록이 자동으로 이루어지기 때문에 첫번 째와 같은 방법을 사용하지 않아도 된다.
하지만 빈 스캐닝의 대상이 되기 위해 InjectionTest와 ConfigurationBeanFactory에 @Component를 붙여줘야 된다.
그리고 빈 스캐닝은 항상 애노테이션을 통한 의존관계주입을 지원한다.(@Resource등의 사용..)
- AnnotationConfigApplicationContext를 사용해서 DI
1 2 3 4 5 6 7 8 | @Component public class InjectionTest { @Resource private ConfigurationBeanFactory configurationBeanFactory; } | cs |
@Resource애노테이션을 필드에도 사용할 수 있다. 수정자를 통하여 의존관계를 주입하는 것과 동일하다.
이 같은 의존관계 주입을 '필드 주입'이라고 한다.
하지만 이 방법은 스프링의 컨테이너 밖에서 테스트 할 때 불편하기 때문에 단위 테스트가 필요한 클래스라면 '필드 주입'보다는 수정자 주입을 사용하는 것이 좋다.
위의 @Resource는 name속성이 지정된 괄호가 포함되어 있지 않는데 이럴때는 등록된 빈의 이름과 위에서 보이는 configurationBeanFactory라는 변수의 이름과 일치하는 빈을 찾아서 의존성 주입을 한다.
만약 name속성을 지정하지 않고, 변수이름과 일치하는 빈을 찾을 수 없을 경우에는 타입명을 이용해 다시 한번 빈을 찾기도 한다.
그러나 name속성을 뺀 @Resource의 사용은 권장하지 않는다. 그러니 name속성을 꼭 쓰자.
- @Autowired
@Autowired는 XML의 타입에 의한 자동와이어링 방식을 생성자, 필드, 수정자(setXXX), 일반메서드에 대하여 지원한다.
이 애노테이션이 부여된 필드, 수정자 등을 만들어두면 스프링이 알아서 DI를 해준다.
@Resource와 다른점은 @Resource는 빈의 이름으로 찾지만 @Autowired는 선언된 타입과 일치하거나 관련있는 빈을 찾는다는 것이다.
- @Autowired를 통한 의존관계 설정 방법
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | //필드 주입 @Component public class InjectionTest { @Autowired private KiaCar kia; } //수정자 프로퍼티 주입 @Component public class InjectionTest { private HyundaiCar hyundai; @Autowired public void setHyundaiCar(HyundaiCar hyundai){ this.hyundai = hyundai; } } //생성자 주입 @Component public class InjectionTest { private KiaCar kia; private HyundaiCar hyundai; @Autowired public InjectionTest(KiaCar kia, HyundaiCar hyundai){ this.kia = kia; this.hyundai = hyundai; } } //일반 메서드 주입 @Component public class InjectionTest { private KiaCar kia; private HyundaiCar hyundai; @Autowired public void config(KiaCar kia, HyundaiCar hyundai){ this.kia = kia; this.hyundai = hyundai; } } | cs |
root-context.xml
1 2 3 | <bean class="dev.carworld.kr.model.KiaCar"></bean> <bean class="dev.carworld.kr.model.HyundaiCar"></bean> | cs |
필드 주입 방식에서는 필드의 타입에 맞는 빈을 스프링 xml 설정에서 찾는다.
수정자, 생성자, 일반메서드 주입방식에서는 매개변수의 타입에 맞는 빈을 스프링 xml 설정에서 찾는다.
@Autowired는 단 하나의 생성자에만 사용할 수 있다.
수정자 방식은 DI해줘야 할 프로퍼티가 늘어날 때마다 수정자를 계속 추가(매개변수가 하나이기 때문)해야 하는 불편 때문에 한번에 필드에 DI해줄 수 있는 생성자 방식을 사용하지만 생성자 방식도 컨테이너 초기화 작업 중에 DI가 되지 않아 에러가 발생할 수 있다는 단점이 있다. 또한 @Autowired로 설정할 수 있는 생성자는 단 하나뿐이다.
하지만 일반 메서드 주입 방식을 이용하면 생성자 방식과는 달리 여러 메서드에 @Autowired를 사용할 수 있고, 수정자 방식처럼 1개의 매개변수만 갖는 것과 달리 여러개의 매개변수를 두어 DI시킬 수 있다.
그러나 일반 메서드 주입방식은 xml을 통하여 의존관계를 설정할 수 없다.
@Autowired를 이용하면 같은 타입의 빈이 하나 이상 존재할 때 그 빈들을 모두 DI받을 수 있다.
필드, 수정자, 일반 메서드 주입방식에서 타입을 배열이나 컬렉션으로 선언하면 된다.
CarInfoProvider라는 인터페이스가 KiaCar와 HyundaiCar라는 클래스에 구현되었다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //Collection으로 DI받기 @Autowired Collection<CarInfoProvider> info; //List로 DI받기 @Autowired List<CarInfoProvider> info; //배열로 DI받기 @Autowired CarInfoProvider[] info; //수정자 메서드의 매개변수를 Set으로 설정 후 DI Set<CarInfoProvider> info; @Autowired public void setCarInfo(Set<CarInfoProvider> info){ this.info = info; } | cs |
위와 같은 방식으로 의존관계 빈을 주입하면 CarInfoProvider가 구현한 빈을 모두 주입 받을 수 있다.
- @Qualifier
Qualifier는 타입 외의 정보를 빈 등록시 추가해서 자동와이어링을 보다 정확하게 제어할 수 있는 보조적 방법이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public interface DataAccessProvider { public void connection(); } public class MysqlDatabase implements DataAccessProvider{ public void connection(){ System.out.println("MySQL에 연결되었습니다."); } } public class OracleDatabase implements DataAccessProvider{ public void connection(){ System.out.println("Oracle에 연결되었습니다."); } } | cs |
1 2 | <bean id="mysql" class="dev.wedding.kr.persis.MysqlDatabase"></bean> <bean id="oracle" class="dev.wedding.kr.persis.OracleDatabase"></bean> | cs |
위와 같이 스프링 xml 설정에 빈 등록을 했을 때 @Resource(name="mysql")과 같이 사용하면 문제가 없으나 @Autowired같이 자동와이어링틀 통해서 빈을 주입할 때는 문제가 발생한다.
자동와이어링 방식은 관계된 타입을 찾아서 빈을 주입하는데 위의 빈 타입은 둘 다 Database이기 때문에 스프링이 이 2개의 빈 중에 어떤 것을 DI할지 판단할 수 없기 때문이다.
1 2 3 4 5 6 7 8 9 10 11 | //정상 @Resource(name="oracle") public void setDatabase(DataAccessProvider data){ data.connection(); } //에러 @Autowired public void setDatabase(DataAccessProvider data){ data.connection(); } | cs |
이런 경우 @Resource만을 사용하는 것이 해결책일 수 있으나, 꼭 @Autowired를 사용해야 할 경우 @Qualifier를 같이 사용하면 해결이 가능하다.
@Qualifier는 해당 빈에 기술되어 있는 <qualifier>태그를 참고한다.
1 2 3 4 | <bean id="mysql" class="dev.wedding.kr.persis.MysqlDatabase"></bean> <bean id="oracle" class="dev.wedding.kr.persis.OracleDatabase"> <qualifier value="useDB"></qualifier> </bean> | cs |
그리고 의존관계 설정을 하는 자바코드에서는
1 2 3 4 5 | @Autowired @Qualifier("useDB") public void setDatabase(DataAccessProvider data){ data.connection(); } | cs |
이와 같이 하면 @Qualifier에 지정된 문자열을 참고하여 등록된 빈에서 이 문자열과 일치하는 <qualifier>태그를 찾아 그 빈을 주입시킨다.
그런데 아래와 같이 빈 등록을 XML에서 하지 않고 @Component같이 스테레오 타입으로 자바 코드 상에서 빈 스캔대상이 되게 한다면 <qualifier>태그를 사용할 수 없기 때문에 XML로는 설정할 방법이 없다
1 2 3 4 5 6 | @Component public class MysqlDatabase implements DataAccessProvider{ public void connection(){ System.out.println("MySQL에 연결되었습니다."); } } | cs |
이럴 때는 다음과 같이 해주면 된다.
1 2 3 4 5 6 7 | @Component @Qualifier("useDB") //<qualifier value="useDB" />와 같다. public class MysqlDatabase implements DataAccessProvider{ public void connection(){ System.out.println("MySQL에 연결되었습니다."); } } | cs |
@Qualifier가 빈을 부여할 수 있는 대상은 필드(멤버변수), 수정자(setXX메서드), 매개변수이다.
그래서 생성자 주입과 일반 메서드 주입에는 @Qualifier를 붙여도 소용이 없다.
@Qualifier를 통해 생성자와 메서드에 의존관계 빈 주입을 하려면 각각의 매개변수 마다 @Qualifier를 붙여야 한다.
1 2 3 4 5 6 7 | @Component public class InjectionTest { @Autowired public InjectionTest(@Qualifier("useDB") DataAccessProvider data){ data.connection(); } } | cs |
'SPRING > 정리' 카테고리의 다른 글
스코프(scope) 빈 (0) | 2016.08.20 |
---|---|
프로토타입(prototype) 빈 (0) | 2016.08.19 |
Spring 빈의 등록 방법 (0) | 2016.08.11 |
[SpringSecurity] 스프링 시큐리티 jquery ajax사용시 로그인 하게 하기 (1) | 2016.07.29 |
요청 파라미터 바인딩 (0) | 2016.04.27 |