본문
IoC & DI
# IoC & DI
- IoC(Inversion Of Control) : 제어의 역전
- DI(Dependency Injection) : 의존성 주입
- 주입 : 주입이란 말은 외부에서라는 뜻을 내포하고 있는 단어다.
자동차 내부에서 타이어를 생산하는 것이 아니라 외부에서 생산된 타이어를 자동차에 장착하는 작업이 주입이다.
# 스프링을 통한 의존성 주입 - @Autowired를 통한 속성 주입
import문 하나와 @Autowired 애노테이션을 이용하면 설정자 메서드를 이용하지 않고도 스프링 프레임워크가 설정파일을 통해 설정자 메서드 대신 속성을 주입하게 된다.
(1) 설정자 메서드
1 2 3 4 5 | Tire tire; public void setTire(Tire tire) { this.tire = tire; } | cs |
(2) @Autowired 적용
1 2 3 4 | import org.springframework.beans.factory.annotation.Autowired; @Autowired Tire tire; | cs |
의사 코드
운전자가 종합 쇼핑몰에서 자동차를 구매 요청한다.
종합 쇼핑몰은 자동차를 생산한다.
종합 쇼핑몰은 타이어를 생산한다.
종합 쇼핑몰은 자동차에 타이어를 장착한다.
종합 쇼핑몰은 운전자에게 자동차를 전달한다.
File -> New -> Spring Project -> Spring MVC Project 선택
Source 01) Tire.java
1 2 3 4 5 | package expert004; public interface Tire { String getBrand(); } | cs |
Source 02) KoreaTire.java
1 2 3 4 5 6 7 8 | package expert004; public class KoreaTire implements Tire { @Override public String getBrand() { return "Korea Tire"; } } | cs |
Source 03) AmericaTire.java
1 2 3 4 5 6 7 8 | package expert004; public class AmericaTire implements Tire { @Override public String getBrand() { return "America Tire"; } } | cs |
Source 04) Car.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package expert004; import org.springframework.beans.factory.annotation.Autowired; public class Car { @Autowired Tire tire; public String getTireBrand() { return "Fitted Tire : " + tire.getBrand(); } } | cs |
Source 05) Driver.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package expert004; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Driver { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("expert004/expert004.xml"); Car car = context.getBean("car", Car.class); System.out.println(car.getTireBrand()); } } | cs |
Source 06) expert004.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <!-- expert004.xml에서 마우스 오른쪽 버튼을 클릭한 후 Open With -> Spring Config Editor를 차례로 선택하자. 편집기가 열리면 하단의 Namespaces탭을 클릭한다. 그 중에서 context를 체크하면 아래의 기울임꼴 두 줄이 자동을 삽입된다. 그 후에 Source 탭으로 돌아와 <context:annotation-config />를 추가하고 car에 해당하는 bean 태그를 수정한 후 저장하면 된다. --> <?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/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-3.1.xsd"> <context:annotation-config /> <bean id="tire" class="expert004.KoreaTire"></bean> <!-- 실행 o --> <bean id="americaTire" class="expert004.AmericaTire"></bean> <!-- 실행 x --> <bean id="car" class="expert004.Car"></bean> </beans> | cs |
Result)
INFO : org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1a93a7ca: startup date [Mon Jan 25 16:48:54 KST 2016]; root of context hierarchy
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [expert004/expert004.xml]
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@548a9f61: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,tire,americaTire,car,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
Fitted Tire : Korea Tire
@Autowired의 의미를 이해해 보자. 이것은 스프링 설정 파일을 보고 자동으로 속서으이 설정자 메서드에 해당하는 역할을 해주겠다는 의미이다. @Autowired를 통해 car의 property를 자동으로 엮어줄 수 있으므로(자동 의존성 주입) 생략이 가능해진 것이다.
# 스프링을 통한 의존성 주입 - @Resource를 통한 속성 주입
@Autowired는 스프링의 어노테이션이다. @Resource는 자바 표준 어노테이션이다. 스프링 프레임워크를 사용하지 않는다면 @Autowired는 사용할 수 없고, 오직 @Resource만을 사용해야 한다. @Autowired와 @Resource는 기능이 동일하지만 자동차에게 타이어는 재료 또는 자원, 부품이라고 할 수 있기 때문에 @Autowired 보다는 @Resource가 더욱 직관적이다. @Autowired를 @Resource으로 변경하는 것 외의 소스코드와 실행결과는 같다.
@Autowired와 @Resource 비교
@Autowired |
@Resource |
|
출처 |
스프링 프레임워크 |
표준 자바 |
소속 패키지 |
org.springframework.beans.factory .annotaion.Autowired |
javax.annotation.Resource |
빈 검색 방식 |
byType 먼저, 못 찾으면 byName |
byName 먼저, 못 찾으면 byType |
특이사항 |
@Qualifier("") 협업 |
name 어트리뷰트 |
byName 강제하기 | @Autowired @Qualifier("tire1") | @Resource(name="tire1") |
스프링이 제공하는 @Autowired와 자바가 제공하는 @Resource 중에서 손 들라고하면 @Resource룰 지지하겠다. 자동으로 주입된다는 의미에서는 @Autowired가 명확해 보이지만 실제 Car 입장에서 보면 @Resource라는 표현이 더 어울린다. 그리고 나중에 스프링이 아닌 다른 프레임워크로 교체되는 경우를 대비하면 자바 표준인 @Resource를 쓰는 것이 유리하다.
그럼 여기서 또 하나의 고민이 생기는데 @Resource는 사실 <bean> 태그의 자식 태그인 <property>태그로 해결될 수 있다.
개발 생산성은 @Resource가 더 좋지만, <property>는 .XML파일만 봐도 DI관계를 손쉽게 확인할 수 있기 때문에 유지보수성이 좋다.
즉, 위의 내용을 정리하자면 아래와 같다.
- @Autowired와 @Resource 중에서는 @Resource 추천
- @Resource와 <property>중에서는 <property> 추천
- 출처 및 참고자료 : 스프링 입문을 위한 자바객체지향의 원리와 이해(김종민 저)
댓글