포스트

(Day 80) Spring IoC Container (XML을 이용한 설정)

PDF

IoC Container

IoC Container = Inversion of Control => Dependency Object Injection

필요한 객체들 (의존하고 있는 객체들)을 본인이 생성하는 것이 아니라, 다른 것에서 생성해서 주입해준다는 것. 그래서 제어가 역전된다는 것.

예시를 들면 아래 코드에서 assignmentDao 객체가 주입받는 의존성이다.

1
2
3
4
5
6
  @RequestMapping("/assignment/add")
  public String add(Assignment assignment) throws Exception {
    System.out.println(assignment);
    assignmentDao.add(assignment);
    return "redirect:list";
  }

How to set IoC Container?

  1. ClassPathXmlApplicationContext

  2. FileSystemXmlApplicationContext

  3. AnnotationConfigApplicationContext

Working principle of Spring IoC Container

.class 바이트코드를 기반으로 해서 객체를 만든다. 그 객체는 쓰지만 맛있다(?)

.class가 객체로 만들어질 때까지, 마치 컨베이어벨트를 지나듯 여러 여러 작업이 수행된다. @ComponentScan 도 처리하고, @Component 도 처리하고…

각 작업들을 수행하는 객체들이 또 따로 있다. 이건 마치 컨베이어 벨트에 각 작업을 수행하는 사람들이 대기하는 것처럼 보인다.

IoC 컨테이너가 구동할 때, 작업을 처리하는 객체들이 모두 있어야 하는 것은 아니다. 작업을 처리할 객체가 존재하는 경우 IoC 컨테이너가 그 객체를 사용해 작업을 수행한다. 없다면 그 작업은 수행되지 않는다.

이것이 IoC 컨테이너가 구동되는 기본적인 흐름이다. 이것이 먼저 이해되어야 한다. 그리고, 어떤 작업자들은 (IoC 컨테이너에서 작업하는 객체들은) 따로 생성하지 않아도 존재한다. 따로 유저가 생성하지 않아도 생성되는 객체가 있다는 것이다. 그런 객체가 무엇인지 알아야 한다.

예를 들면 AnnotationConfigApplicationContext에서는 아래 4개의 객체가 기본적으로 필요한 객체이다.

1
2
3
4
org.springframework.context.annotation.internalConfigurationAnnotationProcessor = org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor = org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.context.event.internalEventListenerProcessor = org.springframework.context.event.EventListenerMethodProcessor
org.springframework.context.event.internalEventListenerFactory = org.springframework.context.event.DefaultEventListenerFactory

internalConfigurationAnnotationProcessor: 기본적인 애너테이션을 확인해서 작업을 처리한다. XML을 쓰는 클래스에서는 필요가 없지만 AnnotationConfigApplicationContext은 필요로 한다.

오늘은 XML로 IoC Container에 객체를 추가하는 방법을 배운다. 다만, 이것을 배우는 것은 XML로 Spring을 설정해주는 것이 대세라는 의미는 아니다. 대세는 Annotation으로 설정하는 것인데, 이전에 개발된 시스템을 관리할 때 필요할수도 있어 한번 보고 가는 것이다.

익명 객체의 별명 (ex02/d)

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 빈의 이름을 지정하지 않을 경우 
         => FQName과 인덱스 번호가 객체의 이름으로 사용된다.
         => FQName#인덱스번호
         => 예) com.eomcs.spring.ioc.ex02.Car#0
         => 익명 객체의 수만큼 인덱스 번호가 증가한다.
    -->
    
    <!-- 
      특히 0번 익명 객체의 별명은 클래스명과 같다.
      즉 com.eomcs.spring.ioc.ex02.Car#0 이름을 가진 익명 객체의 별명은 
         com.eomcs.spring.ioc.ex02.Car 이다.
      그외 익명 객체는 별명이 붙지 않는다.  -->
    <bean class="com.eomcs.spring.ioc.ex02.Car"/>
    <bean class="com.eomcs.spring.ioc.ex02.Car"/>
    <bean class="com.eomcs.spring.ioc.ex02.Car"/>
    <bean class="com.eomcs.spring.ioc.ex02.Car"/>
    
    <!-- 인덱스 번호는 클래스마다 0부터 시작한다. -->
    <bean class="com.eomcs.spring.ioc.ex02.Engine"/>
    <bean class="com.eomcs.spring.ioc.ex02.Engine"/>
    <bean class="com.eomcs.spring.ioc.ex02.Engine"/>
</beans>

클래스마다 인덱스는 0부터 시작한다. 같은 클래스에 대해 첫 번째 익명 객체 만이 별명을 갖는다. 같은 클래스에 대해 두 번째 익명 객체부터는 별명이 없다.

ex03

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 호출할 생성자 지정하기 -->
    
    <!-- 생성자의 파라미터 값을 주지 않으면 기본 생성자가 호출된다.  -->
    <bean id="c1" class="com.eomcs.spring.ioc.ex03.Car"/>
    
    <!-- 다른 생성자 호출하기 : 
      => 파라미터 값을 설정하면 그 값에 맞는 생성자가 선택되어 호출된다.  
      => <constructor-arg/> 엘리먼트를 사용하여 호출될 생성자를 지정할 수 있다.
      => 즉 생성자를 호출할 때 넘겨줄 값을 지정하면 
         스프링 IoC 컨테이너는 그 값을 받을 생성자를 찾아 호출한다. 
      => 파라미터의 개수가 같은 생성자가 여러 개 있을 경우 
         스프링 IoC 컨테이너는 내부의 정책에 따라 적절한 생성자를 선택한다.
         보통 String 타입이 우선이다.-->
    <bean id="c2" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value>티코</value>
        </constructor-arg>
    </bean>
    
    <!-- 한 개의 파라미터 값을 받는 생성자가 여러 개 있을 경우,
         String 타입의 값을 받는 생성자가 우선하여 선택된다. 
         생성자를 정의한 순서는 상관없다.-->
    <bean id="c3" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value>1980</value>
        </constructor-arg>
    </bean>
    
    <!-- 한 개의 파라미터를 가지는 생성자가 여러 개 있을 경우, 
         특정 생성자를 지정하고 싶다면 파라미터의 타입을 지정하라! -->
    <bean id="c4" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    
    <!-- 파라미터가 여러 개인 생성자를 호출할 경우 
         IoC 컨테이너가 가장 적합한 생성자를 찾아 호출한다. -->
    <bean id="c5" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
        <constructor-arg>
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    <bean id="c6" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg>
            <value type="int">1980</value>
        </constructor-arg>
        <constructor-arg>
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
    </bean>
    
    <!-- 파라미터의 값을 설정할 때 이름을 지정해도 
         개발자가 임의로 특정 생성자를 호출하게 제어할 수 없다.
         IoC 컨테이너가 판단하여 적절한 생성자를 호출한다. -->
    <bean id="c7" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg name="cc">
            <value type="int">1980</value>
        </constructor-arg>
        <constructor-arg name="model">
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
    </bean>
    <bean id="c8" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg name="model">
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
        <constructor-arg name="cc">
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    
    <!-- index 속성을 사용하여 파라미터 값이 들어가는 순서를 지정할 수 있다.
         즉 개발자가 어떤 생성자를 호출할 지 지정할 수 있다. -->
    <bean id="c9" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg index="0">
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    <bean id="c10" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg index="1">
            <value type="java.lang.String">소나타</value>
        </constructor-arg>
        <constructor-arg index="0">
            <value type="int">1980</value>
        </constructor-arg>
    </bean>
    
    <!-- 기본 생성자가 없으면 예외 발생! -->
    <!--
    <bean id="e1" class="com.eomcs.spring.ioc.ex03.Engine"/>
    -->
</beans>

XML 객체에서 생성자에 주는 아규먼트 넣기

방법1

방법2

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 호출할 생성자 지정하기 II -->
    
    <!-- 생성자의 파라미터 값을 지정하는 간단한 방법 -->
    <bean id="c1" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg type="java.lang.String" value="티코"/>
    </bean>
    
    <!-- index로 파라미터의 순서를 지정하기 -->
    <bean id="c2" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg index="0" type="java.lang.String" value="티코"/>
        <constructor-arg index="1" type="int" value="890"/>
    </bean>
    
    <!-- value 속성에 지정한 값은 문자열이다.
         생성자를 호출하여 값을 넣을 때 
         IoC 컨테이너는 이 문자열을 파라미터 타입으로 형변환하여 넣는다. 
         단 primitive type에 대해서만 형변환할 수 있다.
         다른 타입은 불가하다 -->
    <bean id="c3" class="com.eomcs.spring.ioc.ex03.Car">
        <constructor-arg index="0" value="티코"/>
        <constructor-arg index="1" value="890"/>
    </bean>
</beans>
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.