본문 바로가기
교재 실습/자바 웹 개발 워크북

148. 어노테이션을 이용한 의존 객체 자동 주입 (2)

by Jint 2022. 11. 10.

3. @Qualifier로 주입할 객체를 지정하기

@Autowired는 프로퍼티에 주입할 수 있는 의존 객체가 여러 개 있을 경우 오류를 발생시킨다. 즉 같은 타입의 객체가 여러 개 있으면 그 중에서 어떤 객체를 주입해야 할지 알 수 없기 때문이다. 이 경우 어노테이션 @Qualifier를 사용하면 손쉽게 해결할 수 있다. @Qualifier는 빈의 이름(또는 아이디)으로 의존 객체를 지정할 수 있다.

이 어노테이션을 사용하려면 빈의 후 처리기(bean post processor)가 필요하다. 이런식으로 하다보면 어노테이션을 사용할 때마다 그 어노테이션을 처리할 객체를 등록해야 하는 불편함이 발생한다. 이런 불편함을 해소하기 위해 스프링에서는 어노테이션 처리와 관련된 빈(bean post processor)을 한꺼번에 등록할 수 있는 방법을 제공한다. 다음과 같이 간단히 태그를 선언하면 된다.

<context:annotation-config/>

실습을 통해 @Qualifier의 사용법을 익혀 본다.

 

- 실습 패키지 생성

exam 패키지 아래에 test19 패키지를 생성한다. test18 패키지의 모든 파일을 복사해온다.

 

- beans.xml 빈 설정 파일

exam/test19/beans.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:p="http://www.springframework.org/schema/p"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd">

	<context:annotation-config/>

	<bean id="hyundaiEngine" class="exam.test19.Engine">
		<constructor-arg value="Hyundai"/>
	</bean>

	<bean id="kiaEngine" class="exam.test19.Engine">
		<constructor-arg value="Kia"/>
	</bean>

	<bean id="car1" class="exam.test19.Car">
		<property name="model" value="Sonata"/>
	</bean>

</beans>

 

xmlns:context="http://www.springframework.org/schema/context"

annotation-config 태그는 context 네임스페이스에 들어 있다. 따라서 이 태그를 사용하기 전에 먼저 네임스페이스를 선언해야 한다.

xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd"

context 네임스페이스의 태그 규칙을 정의한 XML 스키마 파일을 지정한다.

<context:annotation-config/>

context 네임스페이스 준비가 끝났으면 annotation-config 태그를 선언한다. 이 태그를 선언하면 어노테이션 처리를 담당하는 다음의 빈들이 자동 등록되는데, 빈의 후 처리기 - 주요 어노테이션 처리기를 정리한 표이다.

어노테이션 빈의 후 처리기
@Autowired, @Value, @Inject (JSR-330) AutowiredAnnotationBeanPostProcessor
JSR-250 어노테이션(javax.annotation.*) CommonAnnotationBeanPostProcessor
@PersistenceUnit, @PersistenceContext PersistenceAnnotationBeanPostProcessor
@Required RequiredAnnotationBeanPostProcessor
<bean id="hyundaiEngine" class="exam.test19.Engine">
    <constructor-arg value="Hyundai"/>
</bean>

<bean id="kiaEngine" class="exam.test19.Engine">
    <constructor-arg value="Kia"/>
</bean>

Car 객체에서 사용할 Engine 객체를 두 개 준비한다.

<bean id="car1" class="exam.test19.Car">
    <property name="model" value="Sonata"/>
</bean>

Car 객체를 준비한다. engine 프로퍼티의 값은 설정하지 않는다. @Autowired로 선언되었기 때문에 스프링 IoC 컨테이너가 자동으로 Engine 객체를 주입할 것이다.

 

- @Qualifier를 사용하여 의존 객체 지정

어노테이션 @Qualifier를 사용하여 engine 프로퍼티에 들어갈 객체를 지정해 본다.

exam.test19.Car 클래스를 열고 setEngine() 메서드를 다음과 같이 편집한다.

package exam.test19;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class Car {
	
	...
	
	@Autowired(required=false)
	@Qualifier("kiaEngine")
	public void setEngine(Engine engine) {
		this.engine = engine;
	}
	
	...
	
}

@Autowired(required=false)

@Qualifier("kiaEngine")

engine 프로퍼티(setEngine()) 앞에 @Qualifier 선언을 추가한다. 이 어노테이션에 들어가는 값은 beans.xml에 선언된 엔진 객체 중에서 'kiaEngine'을 가리키는 이름이다. 빈 컨테이너는 engine 프로퍼티의 값으로 해당 이름을 갖는 객체를 찾아 주입한다.

 

- 빈 컨테이너 테스트

@Qualifier에 지정된 대로 engine 프로퍼티에 해당 객체가 주입되었는지 확인해 본다. exam.test19.Test 클래스를 다음과 같이 편집한다. beans.xml 파일의 폴더 이름(test19)을 제외하고 나머지 코드는 이전 실습과 같다.

package exam.test19;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
	
	public static void main(String[] args) {
		//IoC 컨테이너 준비하여 빈 생성
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("exam/test19/beans.xml");
		
		Car car1 = (Car)ctx.getBean("car1");
		System.out.println(car1.getEngine());
	}
	
}

Test 클래스를 실행해 보면 다음의 결과를 얻을 수 있다. @Qualifier에 지정한 대로 해당 의존 객체(kiaEngine)가 정확히 주입되었음을 알 수 있다(그림 1).

그림 1 (exam.test18.Test 클래스 실행 결과)

 

4. @Autowired + @Qualifier = @Resource

JSR-250 명세에 정의된 @Resource를 사용하면 더 간단히 특정 의존 객체를 지정할 수 있다. 이름으로 의존 객체를 지정할 경우 이 어노테이션을 사용할 것을 권장한다. 단, @Autowired는 required 속성을 사용하여 프로퍼티 값의 필수 여부를 지정할 수 있지만 @Resource에는 그런 기능이 없으므로 @Resource는 무조건 필수 입력이다. 해당 프로퍼티에 주입할 의존 객체가 없으면 오류가 발생하므로 의존 객체 주입을 선택 사항으로 만들고 싶다면 @Autowired를 사용한다.

 

- 실습 패키지 생성

exam 패키지 아래에 test20 패키지를 생성한다. test19 패키지의 모든 파일을 복사해온다.

 

- @Resource를 사용하여 의존 객체 지정

@Autowired와 @Qualifier 대신 @Resource를 사용하여 의존 객체를 지정해 본다.

exam.test20.Car 클래스를 열고 setEngine() 메서드를 다음과 같이 편집한다.

package exam.test20;

import java.util.Map;

import javax.annotation.Resource;

public class Car {
	
	...
	
	@Resource(name="kiaEngine")
	public void setEngine(Engine engine) {
		this.engine = engine;
	}
	
	...
	
}

@Resource(name="kiaEngine")

@Autowired와 @Qualifier 선언을 제거한다. 대신 @Resource를 선언하고 name 속성에 주입하고자 하는 의존 객체의 이름을 지정한다.

 

- beans.xml 빈 설정 파일

exam/test20/beans.xml 파일을 열고 다음과 같이 편집한다. 이전 실습 소스와 비교해 특별히 바꿀 것은 없고, 각 클래스의 패키지 이름만 test19에서 test20으로 변경한다.

<?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:p="http://www.springframework.org/schema/p"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd">

	<context:annotation-config/>

	<bean id="hyundaiEngine" class="exam.test20.Engine">
		<constructor-arg value="Hyundai"/>
	</bean>

	<bean id="kiaEngine" class="exam.test20.Engine">
		<constructor-arg value="Kia"/>
	</bean>

	<bean id="car1" class="exam.test20.Car">
		<property name="model" value="Sonata"/>
	</bean>

</beans>

 

- 빈 컨테이너 테스트

@Resource가 제대로 동작하는지 확인해 본다. exam.test20.Test 클래스를 다음과 같이 편집한다. beans.xml 파일의 폴더 이름(test20)을 제외하고 나머지 코드는 이전 실습과 같다.

package exam.test20;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
	
	public static void main(String[] args) {
		//IoC 컨테이너 준비하여 빈 생성
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("exam/test20/beans.xml");
		
		Car car1 = (Car)ctx.getBean("car1");
		System.out.println(car1.getEngine());
	}
	
}

실행 결과는 이전 실습과 같다. @Resource에 설정한 대로 해당 의존 객체(kiaEngine)가 정확히 주입되었음을 알 수 있다(그림 2).

그림 2 (exam.test20.Test 클래스 실행 결과)

 

참고도서 : https://freelec.co.kr/book/1674/

 

[열혈강의] 자바 웹 개발 워크북

[열혈강의] 자바 웹 개발 워크북

freelec.co.kr

댓글