티스토리 뷰

반응형

스프링의 특징의 하나로 IoC를 적었었다.

이번 글에서는 IoC와 DI에 대해 보다 구체적으로 정리하였다.

IoC Container

정의

IoC Container는 오브젝트의 생성과 관계설정, 사용, 제거 등의 작업을 대신 해준다하여 붙여진 이름이다.
이때, IoC Container에 의해 관리되는 오브젝트들은 Bean 이라고 부른다. IoC Container는 Bean을 저장한다고 하여, BeanFactory 라고도 불린다.
BeanFactory는 하나의 인터페이스이며, Application Context는 BeanFactory의 구현체를 상속받고 있는 인터페이스이다.
실제로 스프링에서 IoC Container 라고 불리는 것은 Application Context의 구현체이다.

출처: <https://m.blog.naver.com/PostView.nhn?blogId=pjok1122&logNo=221744895053&proxyReferer=https:%2F%2Fwww.google.com%2F>

DI

DI(Dependency Injection)는 말 그대로 클래스끼리 의존하고 주입하는 방식. 즉, 객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입을 시켜주는 방식을 말한다.

계산기 프로그램을 만드는 예제를 보자

계산기 종류에는 프로그래밍용, 공학용, 회계용 등 이 있다. 서비스 클래스가 Calculator 하나만 있지 않다

CalculatorProgram
CalculatorMechanic
CalculatorAccount
....



그리고 어떠한 계산기를 사용할지 제어를 해야한다. 서비스 클래스를 통제(control)하기 위해서 중간 클래스가 필요해진다.

MainClass(실행) - MyCalculator(제어) - 서비스 클래스(Calculator)
조립=>실행!!



이렇게 구현할 수 있다.
그런데, 사용할 계산기 서비스를 바꾸고 싶으면 자바소스를 직접 수정해야 한다

ex) setMyCalculator(new Calculator())에서 새로운 Calculator 생성자를 바꿔야한다.



수정 소요가 많아지면 유지보수에 어려움이 따름이다.
그러므로, 자바 소스를 직접 수정하지 말고, 외부에 틀을 만들어 놓은 후, Main에서 외부의 틀을 불러와 의존 주입을 하게 되면 소스 수정에 부담이 줄어든다. 이 방식을 DI 방식이라 한다.



DI로 계산기를 구현해보자!
먼저, MyCalculator(제어) - 서비스 클래스(Calculator) 코드를 만들었다.

/**
 * @author gogo6
 * 서비스 클래스 -로직(직접 처리)을 담당하고 있다.
 * 이 클래스를 사용하기 위해서 MyCalculator에서는
 * Calculator객체와 데이터 처리 메서드를 만들어야한다.
 *
 */
public class Calculator {

    public void add(int fir,int sec){
        System.out.println("일반용 - add()");
        int result= fir+sec;
        System.out.println(fir+"+"+sec+"="+result);
    }
    public void sub(int fir,int sec){
        System.out.println("일반용 -sub()");
        int result= fir-sec;
        System.out.println(fir+"-"+sec+"="+result);
    }
    public void mul(int fir,int sec){
        System.out.println("일반용 -mul()");
        int result= fir*sec;
        System.out.println(fir+"*"+sec+"="+result);
    }
    public void div(int fir,int sec){
        System.out.println("일반용 -div()");
        int result= fir/sec;
        System.out.println(fir+"/"+sec+"="+result);
    }
}
public class MyCalculator {
    //처리할 데이터 2개 
    //서비스 클래스에 호출하기 위한 객체를 생성!
    //그 객체를 이용해서 메서드를 호출할 때 필요한 
    //메서드 만들기
    private int firstNum;
    private int secondNum;
    private Calculator calculator;  //ctrl+space누르면 클래스이름의 변수명 생성


    //데이터 주입을 위한 setter들이다(생성자 방식은나중에)
    //alt+shift+s,r 
    public void setFirstNum(int firstNum) {
        this.firstNum = firstNum;
    }
    //향후 spring에서 setter을 보고 변수를 찾아가게 된다.<-데이터를 주입할 수 있다.
    public void setSecondNum(int secondNum) {
        this.secondNum = secondNum;
    }
    public void setCalculator(Calculator calculator) {
        this.calculator = calculator;
    }
    ////////기능 구현//////////////////////////
    //MyCalc의 add()를 호출하면 
    public void add(){ 
        //Calc의 add를 호출
        calculator.add(firstNum,secondNum);
    }
    public void sub(){ 
        calculator.sub(firstNum,secondNum);
    }
    public void mul(){ 
        calculator.mul(firstNum,secondNum);
    }
    public void div(){ 
        calculator.div(firstNum,secondNum);
    }

}
<?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="calculator" class="com.koreait.ex0110_spring_di.Calculator"/>

    <!-- setter의 영향을 받는다! -->
    <bean id="myCalculator" class="com.koreait.ex0110_spring_di.MyCalculator">
        <property name="firstNum"  value="10"/>   
        <property name="secondNum">
            <value>2</value>
        </property>
        <property name="calculator"  ref="calculator"/> 
    </bean><!-- 빈즈 참조! -->


</beans>

MainClass(실행)에서 xml에서 빈즈를 가져와서 객체를 생성하자

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class MainClass {

    public static void main(String[] args){

        /*//의존하고 있다.
        MyCalculator mc=new MyCalculator();

        //주입하고 있다.
        mc.setCalculator(new Calculator());
        mc.setFirstNum(10);
        mc.setSecondNum(2);*/

        //#1. xml의 경로(파일명)를 적어준다
        //#2. 파싱 클래스 GenericXmlApplicationContext(경로);
        //#3. AbstractApplicationContext에 다형적 대입
        //#4. getBean() 메서드를 호출해 사용할 객체를 가져오자
        //#5. 메서드 호출!
        String classPath="classpath:applicationCTX_ex04.xml"; //콜론!!!
        AbstractApplicationContext ctx=new GenericXmlApplicationContext(classPath);

        //ctx객체는 xml을 읽어온 상태다.
        //거기서 필요한 객체 bean을 가져와서 인스턴스를 생성해주면 된다.
        MyCalculator mc=ctx.getBean("myCalculator",MyCalculator.class);


        mc.add();
        mc.sub();
        mc.mul();
        mc.div();
    }
}

+ Spring DI/IoC는 어떻게 동작하나요?

IoC(제어의 역전)은 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것으로 코드의 최종호출은 개발자가 제어하는 것이 아닌 프레임워크의 내부에서 결정된 대로 이루어집니다.

DI(의존관계 주입)은 Spring 프레임워크에서 지원하는 IoC의 형태로 클래스 사이의 의존관계를 빈 설정 정보를 바탕으로 컨테이너가 자동으로 연결해줍니다.

스프링에서는 스프링 컨테이너 ApplicationContext를 이용하여 설정 정보를 생성, 등록하고 필요한 객체를 생성자 혹은 setter를 통해 주입합니다.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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
글 보관함