본문 바로가기
Programming/Spring

IoC(Inversion of Control) 컨테이너

by TinKerBellBass 2017. 8. 1.
728x90
반응형
참고 도서
스프링 퀵 스타트
국내도서
저자 : 채규태
출판 : 루비페이퍼 2016.06.30
상세보기



기본 개념 정리

고객이 노트북을 사기 위해 노트북 종합 매장에 왔다. 노트북은 애플 노트북, 엘지노트북이 있고,
노트북에 장착할 수 있는 SSD 는 삼성 SSD, 시게이트 SSD가 있다.
고객은 고민 끝에 삼성 SSD 를 장착한 애플 노트북을 구매.
이 상황을 스프링으로 옮겨 보자.

고객의 행위 - 메인 클래스
노트북 종합 매장 - IoC 컨테이너
노트북- 메인 객체
SSD - 노트북 객체에 주입되는 부품

IoC 개념에 입각해서 스프링스럽게 변화시켜 나가기

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
pakage laptop;

// 고객이 행위를 행하는 메인 클래스 
public class LaptopBuyUser{
    public static void main(String[] args){
         
         // 애플 노트북을 사겠다
        AppleLaptop appleLaptop = new AppleLaptop();
 
        // 애플 노트북에 SSD 장착
         appleLaptop.SSD(); 
    }
}
 
// 고객이 구매하는 컴퓨터 클래스
// 애플 노트북 클래스
class AppleLaptop{
    private String ssd;
    //애플 노트북을 생산
    public AppleLaptop(){        
    }
    public void SSD(){
ssd = "samsung"; //삼성 SSD 장착
        System.out.println(ssd+"장착");
    }
}                        
 
//엘지 노트북 클래스
class LGLaptop{
    private String ssd;
    //엘지 노트북을 생산
    public LGLaptop(){
    }
    public void SSD(){
ssd = "seagate"; //시게이트 SSD 장착
        System.out.println(ssd+"장착");
    }
}

cs

  

다른 고객이 와서 삼성 SSD를 장착한 엘지 노트북을 산다고 하면, 
메인 클래스와 엘지 노트북 클래스는 이렇게 바꾸어야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class LaptopBuyUser{
    public static void main(String[] args){
         
         LGLaptop lgLaptop = new LGLaptop(); 
         lgLaptop.SSD(); 
    }
}
 
class LGLaptop{
    private String ssd;
    public LGLaptop(){
    }
    public void SSD(){
        ssd = "samsung"
        System.out.println(ssd+"장착");
    }
}
cs

==> 다형성을 이용하여 변화

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
pakage laptop;

public class LaptopBuyUser{
    public static void main(String[] args){
 
        Laptop laptop = new AppleLaptop(); 
        //SSD 장착할 때 변화시킬 필요 없음
laptop.SSD(); 
    }
 
interface Laptop{
    public void SSD();
}
 
class AppleLaptop{
    private String ssd;   
    public AppleLaptop(){        
    }
    public void SSD(){
        ssd = "samsung"
        System.out.println(ssd+"장착");
    }
}                        
 
class LGLaptop{
    private String ssd;   
    public LGLaptop(){
    }
    public void SSD(){
        ssd = "seagate"
        System.out.println(ssd+"장착");
    }
}
cs
rmf

여전히 다른 노트북을 사기 위해서는 메인 메소드를 변화 시켜야 한다.

그리고 장착할 SSD 도 변화시켜야 한다.

이렇게 의존 관계가 강한, 결합도가 높은 구조를 느슨하게 하기 위해

스프링은 IoC 컨테이너가 객체 생성과 부품과의 의존 관계를 관리하게 한다.

객체 생성을 IoC 컨테이너가 담당하며, 장착할 부품을 생성된 객체에 주입시킨다(의존성 주입, DI).


==> IoC 컨테이너를 이용하여 결합도 낮추기

 

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
<!-- IoC 컨테이너에서 사용할 bean객체를 XML에서 생성, 파일명: applicationContext.xml-->
<!-- 삼성 SSD를 장착(주입)시켜 애플 노트북(bean 객체)을 생산 -->
<bean id="laptop" class="laptop.AppleLaptop">
    <property name="ssd" value="samsung">
</bean>
 
 
package laptop;
 
public class LaptopBuyUser{
    public static void main(String[] args){
         // IoC 컨테이너를 구동
        AbstractApplicationContext mart 
= new GenericXmlApplicationContext("applicationContext.xml");
 
        // IoC 컨테이너로부터 필요한 객체를 요청(Lookip) 한다
        // getBean("laptop")의 "laptop" 은 bean 객체 설정할 때의 id
        Laptop laptop = (Laptop)mart.getBean("laptop");
        laptop.SSD();          
    }
 
interface Laptop{
    public void SSD();
}
 
class AppleLaptop{
    private String ssd;   
    public AppleLaptop(){        
    }
    public void setSsd(String ssd){
    this.ssd = ssd;
    }
    public void SSD(){        
        System.out.println(ssd+"장착");
    }
}                        
 
class LGLaptop{
    private String ssd;   
    public LGLaptop(){
    }
    public void setSsd(String ssd){
    this.ssd = ssd;
    }
    public void SSD(){         
        System.out.println(ssd+"장착");
    }
}
 
cs

이제 어떤 고객이 와서 어떤 노트북을 사더라도, 어떤 SSD를 장착하더라도,
변화가 일어나는 곳은 IoC 컨테이너에 객체를 생성시키는 XML 설정 파일 뿐이다.

고객의 행위가 일어나는 메인 클래스에서 노트북도 사고, 냉장고도 사고, TV도 살 수 있다면,
종합 마트인 IoC 컨테이너에 노트북 bean 객체, 냉장고 bean 객체, TV bean 객체를 만들고
각각의 bean 객체에 필요한 속성들을 주입시키면 된다.


1. bean 객체 생성

XML
  
1
<bean id="IamId" class="createBean.BeanGo" />
cs

어노테이션
  
1
2
3
4
5
package createBean;
 
  @Component("IamId")
  public class BeanGo {
  }
cs


  어노테이션 설정을 위한 IoC 컨테이너 설정

  

1
<context:component-scan base-package="createBean" />
cs


2. 여러 개의 XML을 통합하여 등록

1
2
3
4
<beans>
<import resource="context-dateSource.xml" />
<import resource="context-transaction.xml" />
</beans>
cs

3. <bean> 엘리먼트 속성

(1) init-method
객체 초기화 작업

1
<bean id="IamId" class="createBean.BeanGo" init-method="initMethod" />
cs

1
2
3
4
5
6
7
package createBean;
 
public class BeanGo {
public void initMethod( ) {
// 객체 초기화 작업
}
}
cs

(2) destroy-method
객체 삭제 직전에 호출

1
<bean id="IamId" class="createBean.BeanGo" init-destroy="destroyMethod" />
cs

1
2
3
4
5
6
7
package createBean;
 
public class BeanGo {
  public void destroyMethod( ) {
  // 객체 삭제 전에 처리할 로직 처리
  }
}
cs

(3) lazy-init
객체가 사용되는 시점에 객체 생성

1
<bean id="IamId" class="createBean.BeanGo" lazy-init="true" />
cs

(4) scope
객체 생성 타입 결정

1
<bean id="IamId" class="createBean.BeanGo" scope="singleton" />
cs
단 하나의 객체만 생성, default 값임(생략하면 singleton)

1
<bean id="IamId" class="createBean.BeanGo" scope="prototype" />
cs
요청이 있을 때마다 새로운 객체 생성

3. 생성자 인젝션(XML)

XML
  
1
2
3
4
5
6
<bean id="IamId" class="createBean.BeanGo">
  <constructor-arg ref="injection" index = "0" />
  <constructor-arg value="valueIn" index ="1" />
  </bean>
<bean id="injection" class="createBean.Injection" />
 <!-- (index 는 생략 가능) -->
cs

주입 받는 클래스
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package createBean;
   
public class BeanGo {
  private Injection injection;
  String valueInjection;
 
  public BeanGo( ) {
  }
 
  public BeanGo(Injection  injection, String valueInjection) {
  this.injection = injection;
  this.valueInjection = valueInjection;
  }
}
cs

주입 되는 클래스
 
1
2
3
4
5
6
7
package createBean;
 
public class Injection {
  
  public Injection( ) {
  }
}
cs

4. Setter 인젝션(XML)

XML
  
1
2
3
4
5
6
<bean id="IamId" class="createBean.BeanGo">
  <property name="injection" ref="injection" />
  <property name="valueInjection" value="valueIn" />
  </bean>
<bean id="injection" class="createBean.Injection" />
<!-- ( setLetsGo( ) { } => name="letsGo"-->
cs

주입 받는 클래스
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package createBean;
   
public class BeanGo {
  private Injection injection;
  String valueInjection;
 
  public BeanGo( ) {
  }
 
  public void setInjection(Injection injection) {
  this.injection = injection;
  }
 
  public void setValueInjection (String valueInjection) {
  this.valueInjection = valueInjection;
  }
}
cs

주입 되는 클래스
  
1
2
3
4
5
6
7
package createBean;
 
public class Injection {
  
  public Injection( ) {
  }
}
cs

5. p 네임스페이스(XML)

1
2
3
4
5
6
<bean id="IamId" class="createBean.BeanGo">
  <property name="injection" ref="injection" />
  <property name="valueInjection" value="valueIn" />
</bean>
<bean id="injection" class="createBean.Injection" />
 
cs

==> p 네임스페이스 사용

1
2
3
<bean id="IamId" class="createBean.BeanGo" p:injection-ref="injection" p:valueInjection="valueIn" />  
<bean id="injection" class="createBean.Injection">
 
cs

6. 컬렉션 객체 설정(XML)

(1) List
중복 값 허용, 순서 있는 자료구조(배열)

1
2
3
4
5
6
7
8
9
<bean id="listBean" class="collectionBean.ListBean">
    <property name="addressList">
        <list>
            <value> 서울시 마포구 상수동 </value>
            <value> 부산시 동구 초량동 </value>
        </list>
    </property>
</bean>
 
cs

1
2
3
4
5
6
7
8
9
package collectionBean;
 
public class ListBean{
    private List<String> addressList;
 
    public void setAddressList(List<String> addressList) {
    this.addressList = addressList;
    }
}
cs

(2) Set
중복 값 허용 하지 않음, 순서 없는 자료구조(집합)

1
2
3
4
5
6
7
8
9
<bean id="setBean" class="collectionBean.SetBean">
    <property name="addressSet">
        <set value-type="java.lang.String">
            <value> 서울시 마포구 상수동 </value>
            <value> 부산시 동구 초량동 </value>
            <value> 부산시 동구 초량동 </value>
        </set>
    </property>
</bean>
cs

1
2
3
4
5
6
7
8
9
package collectionBean;
 
public class SetBean{
    private Set<String> addressSet;
 
    public void setAddressSet(Set<String> addressSet) {
    this.addressSet = addressSet;
    }
}
cs


(3) Map
키와 데이터를 매칭시켜 저장하는 자료구조, 키는 중복 값 허용하지 않음, 값은 중복 값 허용(아이디, 패스워드)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<bean id="mapBean" class="collectionBean.MapBean">
    <property name="mapping">
        <map>
            <entry>
                <key><value> 팅커벨 </value></key>
                <value> 네버랜드 요정섬 </value>
            </entry>
            <entry>
                <key><value> 후크 </value></key>
                <value> 네버랜드  </value>
            </entry>
        </map>
    </property>
</bean>
cs

1
2
3
4
5
6
7
8
9
package collectionBean;
 
public class MapBean{
    private Map<intString> mapping;
 
    public void setMapping(Map<intString> mapping) {
    this.mapping = mapping;
    }
}
cs

(4) Properties
key = value 형태의 데이터 등록

1
2
3
4
5
6
7
8
<bean id="propsBean" class="collectionBean.PropsBean">
    <property name="propsAddress">
        <props>            
            <prop key="팅커벨">네버랜드 요정섬</prop>
            <prop key="후크">네버랜드 </prop>
        </props>    
    </property>
</bean>
cs

1
2
3
4
5
6
7
8
9
10
package collectionBean;
 
public class PropsBean{
    private Properties propsAddress;
 
    public void setPropsAddress(Properties propsAddress) {
    this.propsAddress = propsAddress;
    }
}
 
cs

7. @Autowired 와 @Qualifier (스프링 제공) 그리고 @Resource (자바 제공)

인터페이스

1
2
3
4
5
package injectionAnno

public interface InjectionIF {
}

cs

인터페이스 구현 클래스 A (주입 되는 클래스)
구현
1
2
3
4
5
6
7
package injectionAnno
 
@Component("injectionA")
public class InjectionA implements InjectionIF {
    public InjectionA(){
    }
}
cs

인터페이스 구현 클래스 B (주입 되는 클래스)

1
2
3
4
5
6
7
package injectionAnno
 
@Component("injectionB")
public class InjectionB implements InjectionIF {
    public InjectionB(){
    }
}
cs


주입 받는 클래스


(1) @Autowired @Qualifier

@Autowired 를 통해 주입하는 경우, 인터페이스로 구현된 여러 개의 빈 객체 중에 

하나를 선택 하기 위해서 @Qualifier 필요, 변수의 타입을 기준으로 검색하여 주입

       

1
2
3
4
5
6
7
8
9
10
11
package injectionAnno
 
@Component("createBean")
public class CreateBean {
    @Autowired
    @Qualifier("injectionA")
    private InjectionIF injectionIF;    
 
    public CreateBean(){
    }
}

cs


(2) @Resource = @Autowired + @Qualifier

객체의 이름(name 속성)을 이용하여 주입


1
2
3
4
5
6
7
8
9
10
package injectionAnno
 
@Component("createBean")
public class CreateBean {    
    @Resource(name="injectionA")
    private InjectionIF injectionIF;    
 
    public CreateBean(){
    }
}
cs

(3) 어노테이션과 IoC 컨테이너 병행하여 사용

수정이 필요할 때, IoC 컨테이너만 변경하기 위해 병행


주입되는 클래스의 @Component 제거


1
2
3
4
5
6
7
package injectionAnno
 
public class InjectionA implements InjectionIF {
    public InjectionA(){
    }
}
 
cs


1
2
3
4
5
6
7
package injectionAnno
 
public class InjectionB implements InjectionIF {
    public InjectionB(){
    }
}
 
cs

주입받는 클래스


1
2
3
4
5
6
7
8
9
10
package injectionAnno
 
@Component("createBean")
public class CreateBean {    
    @Autowired
    private InjectionIF injectionIF;    
 
    public CreateBean(){
    }
}

cs


IoC 컨테이너, 주입하고 싶은 클래스만 등록


1
<bean class="injectionAnno.InjectionA" />
cs


8. 반드시 XML로 Bean 객체를 생성해야 하는 경우와 추가 어노테이션

(1) 라이브러리 형태로 제공되는 클래스는 XML을 통해서만 bean 객체를 생성할 수 있다.
    (데이터 베이스 라이브러리 등)

(2) 추가 어노테이션, @Component 대신 사용할 수 있는 어노테이션
@Service 
비지니스 로직을 처리하는 Service 클래스 (XXXServiceImpl 등)

@Repository
데이터베이스 연동을 처리하는 DAO 클래스 (XXXDAO 등)

@Controller
사용자 요청을 제어하는 Controller 클래스 (XXXController 등)



728x90
반응형

'Programming > Spring' 카테고리의 다른 글

Spring Layered Architecture  (0) 2017.08.09
Spring MVC (annotation 기반)  (0) 2017.08.08
Spring MVC (XML 설정 기반)  (0) 2017.08.08
Spring JDBC (JdbcTemplate class)  (0) 2017.08.05
AOP(Aspect Oriented Programming)  (0) 2017.08.02

댓글