의존 주입(Dependency Injection, DI) 이해하기

    의존 주입이라는 용어는 스프링(Spring)에서만 쓰이는 개념은 아니지만, 오늘날 스프링이 이렇게까지 자바(Java) 진영에서 성공할 수 있는 이유 중 하나인 의존 주입에 대해서 알아보도록 하겠습니다. 단어만 볼 때 너무 어려운거 아니야? 라고 생각할 수 있지만 스프링의 기초적인 부분이고 전혀 어려운 것이 아니니 꼭 이해하셨으면 좋겠습니다.

     

    의존 주입(Dependency Injection, DI) 이해하기


    객체에 의존한다

    의존 주입을 이해하기에 앞서, 객체에 의존한다라는 개념을 먼저 이해를 해야 됩니다. 

     

    TestA.java

    package com.tistory.needneo;
    
    public class TestA {
        public void print() {
            System.out.println("test a");
        }
    }

    TestB.java

    package com.tistory.needneo;
    
    public class TestB {
        public void print() {
            System.out.println("test b");
        }
    }

    Main.java

    package com.tistory.needneo;
    
    public class Main {
    
        public static void main(String[] args) {
            TestA testA = new TestA();
            TestB testB = new TestB();
    
            testA.print();
            testB.print();
        }
    }

     

    위 코드는 Main 클래스에서 TestA와 TestB의 print라는 메소드를 호출하는 간단한 로직입니다. 여기서 클래스를 객체로 생각을 전환하시고, Main이라는 객체는 TestA와 TestB가 있어야만 완성이 되는 구조입니다. 그래서 우리는 Main이라는 객체는 TestA 객체와 TestB 객체에 의존한다라고 말을 할 수 있습니다.

     

    그리고 위와 같은 구조는 객체간에 끊을 수 없는 매우 강한 형태의 결합이 이루어지기 때문에 강한 결합(Tight Coupling)이라고 합니다.

     

     

    제어의 역전(Inversion Of Control, IOC)

    그럼 이제 다시 본 포스팅의 주제인 의존 주입에 대해서 알아보도록 하겠습니다. 위 코드의 문제점은 무엇일까요? 첫번째는 객체를 매번 생성(new)해야 된다는 것입니다. 코드안에 new가 존재하는 한 별도의 메모리를 할당해서 객체가 메모리 어딘가에 자리를 잡고 있다는 것이죠. 두번째 문제는 코드의 유지보수성이 떨어질 수 있습니다. 

     

    이렇게 개발자가 직접 new를 선언하여 객체간의 관계를 설정하는 것은 다양한 이유로 좋지 못하기에 스프링에서는 별도의 메모리를 할당할 필요 없이, 유지보수성이 좋게 의존 관계를 설정하는 것을 제공하는데 그것이 바로 의존을 주입하는 DI인 것입니다.

     

    https://docs.jboss.org/exojcr/1.12.3-GA/reference/en-US/html/ch-inversion-of-control.html

     

    스프링은 컨테이너라는 공간에 객체들을 저장할 수 있으며, 필요할 때마다 해당 객체를 꺼내서 원하는 객체에 주입할 수 있습니다. 이러한 객체들은 초기에 한번 생성되며 2번 이상 생성을 할 필요가 없기 때문에 싱글톤(Singleton) 구조이기도 합니다.

     

    위와 같이 개발자가 직접 제어를 하지 않고, 컨테이너가 의존 관계를 주입하기 때문에 객체의 제어권이 넘어갔다는 의미로 제어의 역전(Inversion Of Control)이라 하며 약어로 IOC라고 합니다.

     

    의존 주입의 대표적인 예시

    많은 책들은 의존 주입의 방법으로 다양한 예시를 보여주고 있지만, 현재는 어노테이션 방식으로 통일이 되는 형식이기 때문에 어노테이션의 예시를 보여드리도록 하겠습니다.

     

    @Controller
    public class SampleController {
    	
    	private static final Logger LOGGER = LoggerFactory.getLogger(SampleController.class);
    
    	/** EgovPropertyService */
    	@Resource(name = "propertiesService")
    	protected EgovPropertyService propertiesService;
        
        @Autowired
        protected SampleService sampleService;

     

    위 예시는 전자정부프레임워크(eGovFramework)의 샘플 코드 예시입니다. 코드를 보면 클래스 위에 @Controller라는 어노테이션과 EgovPropertyService라는 전역 변수 위에 @Resource라는 어노테이션이 붙었고, SampleService에는 @Autowired라는 어노테이션이 붙은 것을 알 수 있습니다.

     

    스프링의 경우 이렇게 어노테이션을 이용해서, 스프링에서 관리하는 컨테이너에 보관을 하고 꺼내쓸 수 있습니다. 위의 코드를 보면 SampleController에 Controller라는 어노테이션이 생겼고, 해당 클래스를 컨테이너 박스에 객체를 생성하여 보관을 하게 됩니다.

     

    그리고 기존에 다른 객체를 등록한 SampleService와 EgovPropertyService를 불러들여 해당 전역변수에 결합을 하게 됩니다. 여기서 중요한 지점은 바로 "new"가 없다는 것입니다. 우리가 보통 다른 객체들을 불러들이기 위해서 new를 쓰게 되었는데 해당 코드에는 new가 없습니다.

     

    즉 위와 같이 어노테이션으로 컨테이너의 객체들을 핸들링 하게 되면서 메모리적으로 매우 유리해지기도 하였고, 코드 자체도 심플해지면서 유지보수하기에도 용이해졌다는 것입니다. 이렇게 개발자가 관리를 하지 않는 것을 약한 결합 혹은 느슨한 결합이라 하여 Loose Coupling이라고 합니다. 

     

    반응형

    댓글

    Designed by JB FACTORY