스프링에서는 자바 어노테이션을 이용해 간단히 의존 객체를 주입할 방법을 제공해 준다. 빈의 셋터 메서드에 @Autowired를 선언하면 빈 컨테이너가 셋터의 매개변수 타입과 일치하는 빈을 찾아 자동으로 설정해 준다. 이 기능을 이용하려면 빈 설정 파일에 다음 객체를 선언해야 한다.
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
AutowiredAnnotationBeanPostProcessor 클래스는 빈의 후 처리기(post processor)로서 빈을 생성한 후 즉시 @Autowired로 선언된 셋터를 찾아서 호출하는 역할을 수행한다. 즉 @Autowired가 붙은 프로퍼티에 대해 의존 객체(프로퍼티 타입과 일치하는 빈)를 찾아 주입(프로퍼티에 할당)하는 일을 한다. 실습을 통해 확인해 본다.
1. @Autowired 적용
- 실습 패키지 생성
exam 패키지 아래에 test17 패키지를 생성한다. test16 패키지의 모든 파일을 복사해온다.
- Car의 engine 프로퍼티에 @Autowired 적용
Car 객체는 Engine 객체를 사용한다. Engine 객체는 Car 객체의 의존 객체이다. Engine 객체를 자동 주입하도록 셋터 메서드에 @Autowired를 선언한다.
exam.test17.Car 클래스를 열고 setEngine() 메서드에 @Autowired 어노테이션을 붙인다.
package exam.test17;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
public class Car {
...
@Autowired
public void setEngine(Engine engine) {
this.engine = engine;
}
...
}
- beans.xml 빈 설정 파일
exam/test17/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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="hyundaiEngine" class="exam.test17.Engine">
<constructor-arg value="Hyundai"/>
</bean>
<bean id="car1" class="exam.test17.Car">
<property name="model" value="Sonata"/>
</bean>
<bean id="car2" class="exam.test17.Car">
<property name="model" value="Grandeur"/>
</bean>
</beans>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
▶ 자바 코드로 표현하면?
AutowiredAnnotationBeanPostProcessor tempAutowiredPostProcessor = new AutowiredAnnotationBeanPostProcessor();
@Autowired 어노테이션을 처리할 빈(AutowiredAnnotationBeanPostProcessor)을 선언한다. 이 객체는 빈 컨테이너에 등록된 모든 빈을 조사하여 @Autowired가 붙은 셋터 메서드가 있다면 호출한다. 이때 셋터 메서드에 넘기는 매개변수 값은 빈 컨테이너에서 매개변수 타입으로 찾은 객체이다. 만약 빈 컨테이너에 매개변수 타입에 해당하는 객체가 없다면 예외가 발생하는데 @Autowired가 붙은 프로퍼티는 값을 반드시 설정해야 하기 때문이다. 빈 컨테이너에 매개변수 타입에 해당하는 객체가 두 개 이상 있다면 그 때도 예외가 발생한다. 그 중 어떤 것을 선택해야 할지 알 수 없기 때문이다. 예외 상황이 발생하는 경우는 다음 실습에서 알아본다.
<bean id="hyundaiEngine" class="exam.test17.Engine">
<constructor-arg value="Hyundai"/>
</bean>
▶ 자바 코드로 표현하면?
Engine hyundaiEngine = new Engine("Hyundai");
먼저 Car 객체에서 사용할 Engine 객체를 준비한다.
<bean id="car1" class="exam.test17.Car">
<property name="model" value="Sonata"/>
</bean>
<bean id="car2" class="exam.test17.Car">
<property name="model" value="Grandeur"/>
</bean>
▶ 자바 코드로 표현하면?
//1) 객체 준비
Car car1 = new Car();
Car car2 = new Car();
//2) 프로퍼티 설정
car1.setModel("Sonata");
car2.setModel("Grandeur");
//3)@Autowired 처리 - AutowiredAnnotationBeanPostProcessor
car1.setEngine(hyundaiEngine);
car2.setEngine(hyundaiEngine);
두 개의 Car 객체('car1, car2')를 생성한다. car1의 모델명은 "Sonata"로 설정하고, car2의 모델명은 "Grandeur"로 설정한다. 'engine' 프로퍼티를 설정하는 코드는 없다. 그러나 'engine' 프로퍼티가 @Autowired로 선언되었기 때문에, @Autowired 어노테이션 처리기 AutowiredAnnotationBeanPostProcessor 객체에 의해 hyundaiEngine 빈이 자동 설정된다.
- 빈 컨테이너 테스트
Car 객체에 Engine 객체가 자동으로 설정되었는지 확인해 본다. test16 패키지에서 복사해 온 테스트 클래스 exam.test17.Test를 다음과 같이 편집한다.
package exam.test17;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//IoC 컨테이너 준비하여 빈 생성
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("exam/test17/beans.xml");
Car car1 = (Car)ctx.getBean("car1");
Car car2 = (Car)ctx.getBean("car2");
System.out.println(car1);
System.out.println(car2);
}
}
출력 결과를 보면 'car1', 'car2' 모두 정상적으로 엔진 객체가 할당된 것을 알 수 있다.
2. @Autowired의 required 속성
프로퍼티(셋터 메서드)에 대해 @Autowired를 선언하면 해당 프로퍼티는 기본으로 필수 입력 항목이 된다. 만약 프로퍼티에 주입할 의존 객체를 찾을 수 없다면 예외가 발생한다. @Autowired의 required 속성을 이용하면 필수 입력 여부를 조정할 수 있다. required 속성을 false로 설정하면 프로퍼티에 주입할 의존 객체를 찾지 못하더라도 예외가 발생하지 않는다. 실습을 통해 확인해 본다.
- 실습 패키지 생성
exam 패키지 아래에 test18 패키지를 생성한다. test17 패키지의 모든 파일을 복사해온다.
- beans.xml 빈 설정 파일
exam/test18/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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="car1" class="exam.test18.Car">
<property name="model" value="Sonata"/>
</bean>
</beans>
Engine 빈을 선언하지 않았다. 따라서 'car1'의 engine 프로퍼티에 주입할 객체를 찾지 못해 예외가 발생할 것이다.
- 빈 컨테이너 테스트
@Autowired로 선언한 engine 프로퍼티에 값을 주입하지 못할 때 예외가 발생하는 상황을 확인해 본다. exam.test18.Test 클래스를 다음과 같이 편집한다.
package exam.test18;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//IoC 컨테이너 준비하여 빈 생성
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("exam/test18/beans.xml");
Car car1 = (Car)ctx.getBean("car1");
System.out.println(car1.getEngine());
}
}
앞의 코드를 실행하면 beans.xml을 로딩하여 객체를 준비하는 과정에 예외가 발생할 것이다. 다음은 실행 결과의 일부이다(그림 2).
출력된 예외 정보 중에서 다음 문장에 주목하기 바란다.
Error creating bean with name 'car1':
제일 먼저 보이는 메시지가 'car1'이라는 이름을 가진 빈을 생성하는데 실패했다는 것이다. 그리고 이어서 그 이유가 나오는데 의존 객체를 자동 주입하는데 실패했다고 한다. 구체적으로 어떤 프로퍼티(setEngine())를 호출하려다가 실패했는지 언급하고 있다. 이렇듯 오류 메시지만 봐도 왜 오류가 발생했는지 그 이유를 어렵지 않게 파악할 수 있다.
- @Autowired의 required 속성 사용
이번에는 required 속성을 사용하여 프로퍼티를 선택 항목이 되게 만들어 본다.
exam.test18.Car 클래스를 열고 setEngine() 메서드에 선언된 @Autowired 어노테이션을 다음과 같이 변경한다.
package exam.test18;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
public class Car {
...
@Autowired(required=false)
public void setEngine(Engine engine) {
this.engine = engine;
}
...
}
@Autowired 어노테이션의 required 속성값을 false로 설정한다.
다시 exam.test18.Test 클래스를 실행한다. 이전과 달리 engine 프로퍼티에 주입할 객체가 없어도 오류가 발생하지 않는다.
앞의 실행 결과는 다음 코드 때문이다.
Car car1 = (Car)ctx.getBean("car1");
System.out.println(car1.getEngine());
'car1' 빈을 찾아서 engine 프로퍼티의 값을 출력해 보니 null인 것이다. 이전과 달리 engine 프로퍼티에 주입할 의존 객체를 찾지 못해도 오류가 발생하지 않는다.
참고도서 : https://freelec.co.kr/book/1674/
[열혈강의] 자바 웹 개발 워크북
[열혈강의] 자바 웹 개발 워크북
freelec.co.kr
'교재 실습 > 자바 웹 개발 워크북' 카테고리의 다른 글
149. 빈 자동 등록 (1) | 2022.11.11 |
---|---|
148. 어노테이션을 이용한 의존 객체 자동 주입 (2) (2) | 2022.11.10 |
146. 날짜 값 주입 (2) (0) | 2022.11.08 |
145. 날짜 값 주입 (1) (1) | 2022.11.07 |
144. 빈의 범위 설정 (0) | 2022.11.07 |
댓글