by-nc-sa     개발자, DBA가 함께 만들어가는 구루비 지식창고!

IoC(Inversion of Control)의 이해




IoC(Inversion of Control)의 이해

1. IoC(제어의 역전현상)의 이해

  • IoC는 Inversion of Control의 약자이다.
  • 우리나라 말로 직역해 보면 "역제어"라고 할 수 있다. 즉 제어의 주체가 바뀌었다. 누구로? Ioc 컨테이너로

1.1 제어의 역전현상 이란?

  • 기존에 자바 기반으로 어플리케이션을 개발할 때 자바 객체를 생성하고 서로간의 의존 관계를 연결시키는 작업에 대한 제어권은 보통 개발되는 어플리케이션에 있었다.
  • 그러나 Servlet, EJB 등을 사용하는 경우 Servlet Container, EJB Container에게 제어권이 넘어가서 객체의 생명주기(Life Cycle)를 Container들이 전담하게 된다.
  • 이처럼 IoC에서 이야기하는 제어권의 역전이란 객체의 생성에서부터 생명주기의 관리까지 모든 객체에 대한 제어권이 바뀌었다는 것을 의미한다.

1.2 IoC의 장/단점

장점
  • 인터페이스 기반 설계가 가능.
  • 컴퍼넌트 재사용성 증가
  • 체계적이고 효율적인 Dependency 관리
단점
  • 제어구조가 반대로 되어 있으므로 이해하기 어려운 코드가 될 수 있음

1.3 컨테이너(Container)란?

Servlet Container
  • Servlet의 생성, 생성 후 초기화, 서비스 실행, 소멸에 관한 모든 권한을 가지면서 Servlet의 생명주기를 관리한다.
  • 개발자들이 직접 Servlet을 생성하고 서비스하지는 않는다.
  • 멀티 스레딩을 지원하여 클라이언트의 다중 요청을 알아서 처리해준다.
  • 대표적인 Conatainer에는 Tomcat, jetty, jboss 등이 있다
EJB Container
  • EJB(세션빈, 엔티티빈)의 생성, 생성 후 초기화, 서비스 실행, 소멸에 관한 모든 권한을 가지면서 EJB의 생명주기를 관리한다.
  • Transaction, Security, EJB Pooling등의 추가적인 기능을 제공하고 있다.
IoC Container
  • IoC를 구현하는 프레임워크로 객체를 관리하고, 객체의 생성을 책임지고, 의존성을 관리하는 컨테이너 이다.
  • 즉 POJO 생성, 초기화, 서비스 소멸에 관한 모든 권한을 가지면서 POJO의 생명주기를 관리한다.
  • 개발자들이 직접 POJO를 생성할 수도 있지만, 모든 권한을 Container에게 맡긴다.

1.4 Ioc 분류체계

2. DI(Dependency Injection) 및 DL(Dependency Lookup)의 이해

2.1 Dependency Injection(의존성 삽입)의 이해

  • Dependency Injection이란 각 클래스 사이의 의존관계를 빈 설정(Bean Definition)정보를 바탕으로 컨테이너가 자동적으로 연결해주는 것을 말한다.
  • 개발자들은 단지 빈 설정파일(저장소 관리 파일)에서 의존관계가 필요하다는 정보를 추가하기만 하면 된다.
Dependency Injection의 장점
  • 코드가 단순해 진다.
  • 컴포넌트간의 결합도가 제거된다.
  • 테스트가 유리하다. Mock/Stub 사용 가능
Dependency Injection의 분류
  • Constructor Injection : 컴퍼넌트의 dependency 가 constructor의 argument를 통해 제공되는 방식
  • Setter Injection : 컴퍼넌트의 dependency 가 JavaBean-style setter를 통해 제공되는 방식
  • Method(Interface) Injection : 컴퍼넌트의 dependency 가 일반 메소드를 통해서 제공되는 방식 (거의 사용하지 않으므로 배우지 않겠다.)
  • Setter를 통해 의존성이 있는 객체를 삽입하는 방법
    Setter Dependency Injectionl
    <!-- JAVA -->
    public class ObjectListBO {
    
        private ObjectListDAO objectListDAO;
    
        // Setter Dependency Injection
    public void setObjectListDAO(ObjectListDAO objectListDAO) {
          this.objectListDAO = objectListDAO;
        }
        public List<Emp> getEmployeeList() {
            return objectListDAO.selectEmployeeList();
        }
    } 
    
    <!-- applicationContext.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        default-autowire="byName">
       
      <bean id="objectListBO" class="com.spring.ioc.bo.ObjectListBO" >
        <property name="objectListDAO" ref="objectListDAO" />
      </bean>
    
       <bean id="objectListDAO" class="com.spring.ioc.dao.ObjectListDAO" />
    
    </beans>
    
  • Constructor를 통해 의존성이 있는 객체를 삽입하는 방법
    Setter Dependency Injectionl
    <!-- JAVA -->
    public class ObjectListBO {
    
        private ObjectListDAO objectListDAO;
    
        // constructor Dependency Injection
        public ObjectListBO(ObjectListDAO objectListDAO) {
            this.objectListDAO = objectListDAO;
        }
    
        public List<Emp> getEmployeeList() {
            return objectListDAO.selectEmployeeList();
        }
    } 
    
    <!-- applicationContext.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        default-autowire="byName">
          
      <bean id="objectListBO" class="com.spring.ioc.bo.ObjectListBO" >
        <constructor-arg ref="objectListDAO" />
      </bean>
    
      <bean id="objectListDAO" class="com.spring.ioc.dao.ObjectListDAO" />
    </beans>
    
    

2.2 DI XML <bean> 태그

<property>
  • Setter Dependency Injection 에서 사용
  • name속성은 setter 메소드 명
  • ref 속성은 의존성 주입할 객체 명
  • value는 Bean이 아닌 Object를 의존성 주입 할 때 사용
<constructor-arg>
  • Constructor Dependency Injection에서 사용
  • ref 속성은 의존성 주입할 객체 명
  • value는 Bean이 아닌 Object를 의존성 주입 할 때 사용
  • type 속성은 파라미터 타입을 명시 (type=java.lang.String)

2.3 DL의 이해

  • 컨테이너 API 를 이용해 저장소에 의해 관리되고 있는 bean을 개발자들이 직접 Lookup 하여 사용한다.
  • Dependency Pull 이라고도 불리운다.
  • 자바 개발자들에게 친숙한 전통적인 접근법 이다.
  • Dependency Lookp 예제
Dependency Lookup
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/applicationContext-ioc.xml");
ObjectListDAO objectListDAO = (ObjectListDAO) ctx.getBean("objectListDAO");

3. Bean Scope

3.1 Bean Scope란

  • Bean Scope는 객체가 유효한 범위로 아래 5가지의 scope가 있다.
    Scope 설명
    singleton 하나의 Bean 정의에 대해서 Spring IoC Container 내에 단 하나의 객체만 존재한다.
    prototype 하나의 Bean 정의에 대해서 빈을 사용할 때 마다 객체를 생성 한다.
    request HTTP 요청마다 객체를 생성 한다. 즉 HTTP request의 생명주기 안에 단 하나의 객체만 존재한다
    session HTTP 세션마다 객체를 생성 한다. 즉 HTTP Session의 생명주기 안에 단 하나의 객체만 존재한다
    global-session 글로벌 HTTP 세션 안에 단 하나의 객체만 존재한다

3.2 Singleton Scope

  • Bean이 singleton인 경우, 단지 하나의 공유 객체만 관리된다.
  • Singleton scope은 Spring의 기본(default) scope이다.
  • Container 당 하나의 객체라는 의미에서 singleton 이다. JVM의 classloader당 하나의 객체라는 의미의 GoF의 Singleton과는 다르다
Singleton Scope 예
 <bean id="articleBO" class="com.oracleclub.ArticleBOImpl"/>

 <bean id="articleBO" class="com.oracleclub.ArticleBOImpl" scope="singleton"/>
 
 <bean id="articleBO" class="com.oracleclub.ArticleBOImpl" singleton="true"/>

3.3 Prototype Scope

  • prototype scope로 정의된 bean은 필요한 매 순간 새로운 bean 객체가 생성된다.
  • bean을 요청 할 때 DI 되거나 getBean(String)에 의해 호출 될 때 마다 새로운 객체를 만들어 준다.
Prototype Scope 예
 <bean id="articleBO" class="com.oracleclub.ArticleBOImpl" scope=" prototype"/>
 
 <bean id="articleBO" class="com.oracleclub.ArticleBOImpl" singleton="false"/>

3.4 기타 Scope

  • request, session, global session scope을 사용하기 위해서는 추가적인 설정이 필요하다.
  • Servlet 2.4+ web container를 사용하고, JSF나 Struts 등과 같이 Spring의 DispatcherServlet의 외부에서 요청을 처리하는 경우, 다음 javax.servlet.ServletRequestListener를 'web.xml' 파일에 추가해야 한다.
  • struts를 사용하는 경우 web.xml의 예
    web.xml 예
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    
Request Scope
  • 아래는 Request Scope의 설정 예이다.
    Request Scope 예
    <bean id="articleWriteAction" class="com.oracleclub.article.action.ArticleWriteAction" scope="request"/> 
     
Session Scope
  • 아래는 Session Scope의 설정 예이다.
    Session Scope 예
    <bean id="userInfo" class="com.oracleclub.user.UserSessionInfo" scope="session"/>  
     
Global Session Scope
  • 아래는 Global Session Scope의 설정 예이다.
    Global Session Scope 예
    <bean id="userInfo" class="com.oracleclub.user.UserSessionInfo" scope="globalSession"/> 
     

4. BeanFactory와 ApplicationContext

4.1 BeanFactory

  • BeanFactory 인터페이스는 Spring IoC Container의 기능을 정의하고 있는 기본 인터페이스이다.
  • Bean의 생성 및 종속성 주입, 생명주기 관리등의 기능을 제공한다.
BeanFactory 예
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
HelloService service = (HelloService) factory.getBean("helloService");
 

4.2 ApplicationContext

  • BeanFactory 인터페이스를 상속받는 ApplicationContext는 BeanFactory가 제공하는 기능외에 Spring AOP, 메시지 리소스처리(국제화에사용됨), 이벤트 처리등의 기능을 제공한다.
  • 모든 ApplicationContext 구현체는 BeanFactory의 기능을 모두 제공하므로, 특별한 경우를 제외하고는 ApplicationContext를 사용하는 것이 바람직하다.
  • Spring Framework는 다수의 ApplicationContext 구현체를 제공한다.
  • applicationContext를 구현한 클래스들
    • AbstractApplicationContext
    • AbstractRefreshableApplicationContext
    • AbstractRefreshablePortletApplicationContext
    • AbstractRefreshableWebApplicationContext
    • AbstractXmlApplicationContext
    • ClassPathXmlApplicationContext
    • FileSystemXmlApplicationContext
    • GenericApplicationContext
    • GenericWebApplicationContext
    • StaticApplicationContext
    • StaticPortletApplicationContext
    • StaticWebApplicationContext
    • XmlPortletApplicationContext
    • XmlWebApplicationContext

문서정보

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.