DI (Dependency Injection)
- 객체가 생성될 때 필요한 의존성을 설정 파일(XML)이나 애노테이션을 통해 외부에서 주입받는 개념
- 객체사이의 의존 관계를 자기 자신이 아닌 외부에 의해서 설정된다는 개념
- 스프링에서는 설정파일을 사용하여 손쉽게 객체간의 의존관계를 설정하기에 스프링을 DI 컨테이너 라고 부르기도 함
- DI 컨테이너의 역할 : 어떤 클래스가 필요로 하는 인스턴스를 자동으로 생성, 취득하여 연결
- DI 컨테이너가 인스턴스를 생성하도록 하려면 프로그램 소스 내부에서 new 로 직접 생성하지 않고 설정파일에서 필요로 하는 클래스의 정보를 설정해 주어야한다
각 클래스간의 의존관계를 관리하기 위한 방법
- Constructor Injection
- Setter Injection
1. Constructor Injection
- 생성자를 통해서 의존 관계를 연결
- 생성자를 통해서 의존 관계를 연결하기 위해서는 XML 설정 파일에서 <bean>요소의 하위요소로 <constructor-arg>를 추가해야 한다
- 빈(bean)을 생성할 때 해당 객체의 생성자(constructor)에 인자를 전달하는 방식으로 값을 주입할 때 사용
① 전달인자가 2개 이상인 경우
public class Foo {
public Foo(int a, String b) { }
}
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
<constructor-arg>
<value>25</value>
</constructor-arg>
<constructor-arg value="Hello" />
</bean>
② index 속성을 이용하여 지정
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
<constructor-arg index="1" value="Hello" />
<constructor-arg index="0">
<value>25</value>
</constructor-arg>
</bean>
③ type 속성을 이용하여 지정
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
<constructor-arg type="int" value="25" />
<constructor-arg type="java.lang.String" value="Hello" />
</bean>
④ 객체를 전달할 경우에는 ref 요소를 사용
public class Foo {
private Bar bar;
public Foo(Bar bar){
this.bar = bar;
}
}
public class Bar { }
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
<constructor-arg>
<ref bean="bar" />
</constructor-arg>
</bean>
<bean id="bar" class="Bar" />
2. Setter Injection
- setter 메서드를 이용하여 의존 관계를 연결
- <property>요소의 name 속성을 이용하여 값의 의존 관계를 연결시킬 대상이 되는 필드값을 지정한다
① 전달인자가 2개 이상인 경우
public class Foo {
private int a
private String b;
public void setA(int a) { }
public void setB(String b) { }
}
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
<property name="a">
<value>25</value>
</property>
<property name="b" value="Hello" />
</bean>
② 객체를 전달할 경우에는 ref 요소를 사용
public class Foo {
private Bar bar;
public void setBar(Bar bar){
this.bar = bar;
}
}
public class Bar { }
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
<property name="bar" ref="bar"></property>
</bean>
<bean id="bar" class="Bar" />
bean 생성 방법
- <bean> 태그
- 클래스 위 @Component 어노테이션 사용
- 메서드 위 @Bean 어노테이션 사용
1. <bean> 태그
- applicationContext.xml
<bean id="messageBeanImpl" class="sample01.MessageBeanImpl" >
<constructor-arg>
<value>사과</value>
</constructor-arg>
<!-- messageBeanImpl.setCost(5000); -->
<!-- SetCost(int cost) 에서 앞, 뒤 빼고 소문자로 작성 -->
<property name="cost">
<value>5000</value>
</property>
<!-- messageBeanImpl.setQty(3); -->
<!-- SetQty(int qty) 에서 앞, 뒤 빼고 소문자로 작성 -->
<property name="qty">
<value>3</value>
</property>
</bean>
2. 클래스 위 @Component 어노테이션 사용
- applicationiContext.xml
<context:component-scan base-package="sample01"></context:component-scan>
// "이 패키지에서 어노테이션으로 빈을 설정한다"
// 빈 설정은 아님. 빈 설정을 위해 어노테이션 을 쓰겠다
- 인터페이스 구현 java 파일
@Component // 스프링에서 **빈(Bean)**으로 관리할 클래스
@Value // 속성 주입 (값 주입)
@Autowired // 자동 의존성 주입
@Component | @ComponentScan 을 사용하면 특정 패키지에서 @Component 가 붙은 클래스를 자동으로 스캔하고 빈으로 등록
|
@Value | 주입할 수 있는 값:
|
@Autowired | 주입 방식:
|
3. 메서드 위 @Bean 어노테이션 사용
- applicationiContext.xml
<context:component-scan base-package="spring.conf"></context:component-scan>
- SpringConfiguration.java
@Configuration // 나는 일반 자바파일이 아니다; 스프링 설정파일 취급
public class SpringConfiguration {
@Bean // 함수로 설정
public MessageBeanImpl messageBeanImpl() {
return new MessageBeanImpl("사과");
}
}
/** return 을 받는 함수는 앞에 get이 붙는 규칙 따를 때 */
@Configuration // 나는 일반 자바파일이 아니다; 스프링 설정파일 취급
public class SpringConfiguration {
@Bean(name="MessageBeanImpl")
public MessageBeanImpl getMessageBeanImpl() {
return new MessageBeanImpl("사과");
}
MessageBeanImpl getMessageBeanImpl = new MessageBeanImpl("사과");
}
⚒️ 예제
Chapter02_XML
Java | applicationContext.xml | |
sample01 | // MessageBeanImpl 인스턴스 생성 (생성자 주입) MessageBeanImpl messageBeanImpl = new MessageBeanImpl("사과"); // setter 메서드로 필드 값 설정 messageBeanImpl.setCost(5000); messageBeanImpl.setQty(3); |
bean id="messageBeanImpl" class="sample01.MessageBeanImpl" > <constructor-arg> <value>사과</value> </constructor-arg> <!-- messageBeanImpl.setCost(5000); --> <!-- SetCost(int cost) 에서 앞, 뒤 빼고 소문자로 작성 --> <property name="cost"> <value>5000</value> </property> <!-- messageBeanImpl.setQty(3); --> <!-- SetQty(int qty) 에서 앞, 뒤 빼고 소문자로 작성 --> <property name="qty"> <value>3</value> </property> </bean> |
sample02 | // CalcAdd 인스턴스 생성 (생성자 주입) CalcAdd calcAdd = new CalcAdd(25, 36); // CalcMul 인스턴스 생성 (기본 생성자) CalcMul calcMul = new CalcMul(); // setter 메서드로 필드 값 설정 calcMul.setX(25); calcMul.setY(36); |
<!-- 생성자 주입(Constructor Injection)을 사용하는 CalcAdd bean 정의 --> <bean id="calcAdd" class="sample02.CalcAdd"> <constructor-arg value="25" /> <constructor-arg value="36" /> </bean> <!-- 세터 주입(Setter Injection)을 사용하는 CalcMul bean 정의 --> <bean id="calcMul" class="sample02.CalcMul"> <property name="x" value="25" /> <property name="y" value="36" /> </bean> |
sample03 | // SungJukImpl 인스턴스를 생성 SungJukImpl sungJukImpl = new SungJukImpl(); |
<!-- SungJukDTO: Setter Injection --> <bean> <property name="name" value="홍길동"/> <property name="kor" value="97"/> <property name="eng" value="100"/> <property name="math" value="95"/> </bean> <!-- SungJukImpl: Constructor Injection --> <bean id="sungJuk" class="sample03.SungJukImpl"> <constructor-arg ref="sungJukDTO"/> </bean> |
// D:\Spring\work | |
Chapter02_XML/sample01 | XML bean 생성 |
Chapter02_ANNO/sample01 | @Component Annotation bean 생성 |
Chapter02_ANNO_Bean/sample01 | @Bean Annotation bean 생성 |
// D:\Spring\work | |
Chapter02_XML/sample02 | XML bean 생성 |
Chapter02_ANNO/sample02 | @Component Annotation bean 생성 |
Chapter02_ANNO_Bean/sample02 | @ Bean Annotation bean 생성 |
// D:\Spring\work | |
Chapter02_XML/sample03 | XML bean 생성 |
Chapter02_ANNO/sample03 | @Component Annotation bean 생성 |
Chapter02_ANNO_Bean/sample03 | @ Bean Annotation bean 생성 |
// D:\Spring\work | |
Chapter02_XML/sample04 | XML bean 생성 |
Chapter02_ANNO/sample04 | Annotation bean 생성 |
Chapter02_ANNO_Bean/sample04 | @ Bean Annotation bean 생성 |
// D:\Spring\wor | |
Chapter02_XML/sample05 | XML bean 생성 |