의존성 주입

반응형
반응형

스프링에서는 IOC라고도 불리며,
DI라고도 불린다.
엄밀리 따진다면, 살짝 다를 수 있는데, 그건 어떻게 해석하냐의 차이라고 생각한다.
IOC : 역전 컨테이너 
DI : 의존성 제어
즉, IOC는 컨테이너이고, DI는 기술이다. 뭐 따지고 보면 같기 때문에 다르다고 말한다는 건 아닌 것 같다.

아무튼
의존성을 주입하는 방법은 굉장히 많이 존재한다.

몇 가지 예시를 살펴보자.

public class SubHello {
    public SubHello() {
        System.out.println("sub Hello");
    }
}

public class Hello {
    public Hello() {
        SubHello subHello = new SubHello();
        System.out.println("hello?");
    }
}

public class Client {
    public static void main(String[] args) {
        Hello hello = new Hello();
    }
}

간단하게 설명하면,
SubHello는 Hello를 실행해야 생성이 된다.
이렇게 되면 SubHello는 Hello에 의존적일 수 밖에 없다.
그림을 그려보면

하지만, 항상 SubHello를 실행하려고, Hello를 실행한다는 건 별로 좋은 방법은 아닌것 같다.
물론, 무조건 Hello => SubHello를 실행해야되는 코드를 작성하는 거라면 이것도 나쁘지 않을 수도 있지만,
이게 가장 나쁜 이유는 Hello안에 다른 클래스를 실행이 불가능하다는 것이다.

예를들어, 나는 SubHello를 상속받은 다른 클래스를 넣고 싶다면, 
위 코드에서 Hello생성자 부분을 수정해야된다.

그래서 코드를 이렇게 바꿨다.

public class Hello {
    public Hello() {
        System.out.println("hello?");
    }
}

public class SubHello {
    public SubHello() {
        System.out.println("sub Hello");
    }
}

public class Client {
    public static void main(String[] args) {
        Hello hello = new Hello();
        SubHello subHello = new SubHello();
    }
}

이렇게 만들고, 나니 의존성 문제는 해결되었다.
하지만, Hello와 SubHello가 따로 놀기 때문에 Hello하나로 SubHello를 조작하는 것은 매우 힘든것 같다.
즉, 이런것을 결합도가 낮다고 할 수 있다.
왜냐하면 Hello와 SubHello는 아무런 상관이 없기 때문이다.

그림으로 그려보면 다음처럼 그릴 수 있다.

자 그럼 정리해보자.
 1. 코드의 의존도는 낮추면서
 2. 코드의 결합도를 높이고 싶다.

마지막으로 코드를 이렇게 수정하였다.

public class SubHello {
    public SubHello() {
        System.out.println("sub Hello");
    }
}

public class Hello {

    private SubHello subHello;

    public Hello(SubHello subHello) {
        this.subHello = subHello;
        System.out.println("hello?");
    }
}

public class Client {
    public static void main(String[] args) {
        SubHello subHello = new SubHello();
        Hello hello = new Hello(subHello);
    }
}

이제 위에서 발생했던 문제를 어떻게 해결했는지 살펴보자.
1. 코드의 의존도가 높았던 문제
어떻게 의존도를 낮췄는지 살펴보자.
이제 SubHello는 Hello가 실행되지 않아도 단독으로 실행할 수 있다.

2. 코드의 결합도가 낮았던 문제
결합도는 Hello의 생성자에서 주입을 받게끔수정하였다.
이제 Hello를 실행해야 SubHello를 실행할 수 있다.
근데, 이것은 첫번째와 같다보인다.
맞다. 같아보이는게 아니라 같다.

첫 번째의 문제점은 결합도는 오히려 높았다.
즉, 의존도는 높았고, 결합도도 높았다고 말할 수 있다.

내침김에 두 번째도 말해보면,
두번째는 의존도는 낮고, 결합도도.낮았다고 말할 수 있다.

어떻게 보면 2가지의 장점만 사용한것이 DI라는 기술이고,
스프링에서는 IOC라는 기술로 DI를 제공하고 있다.

이것을 그림으로 그려보면

스프링에서 사용되는 DI

바로 @AutoWrite계열을 사용하면 된다.
계열이라고 표현한 이유는 @AutoWrite말고 @Injection, @Resouce같은것들도 있는데 
@AutoWrite가 대표적이기 때문이다.

이것을 사용하기 위해서는 빈 객체로 만들어야 한다.
저번장에서 빈 객체를 만드는 방법에 대해 
설명했으니, 간단히 말해, 클래스에 @Component => @Service, @Repository계열을 추가해주면 된다.

@Service
public class Hello {
    @Autowired
    private SubHello subHello;
    
     public Hello() {
        System.out.println("Hello");
    }

}

@Service
public class SubHello {
    public SubHello() {
        System.out.println("sub Hello");
    }
}

@SpringBootTest
class StudyTest {

    @Autowired
    private Hello hello;

}

이유는 모르겠지만, main문에서는 실행이 되지 않는 관계로 그냥 찾기 귀찮고, 굳이 메인문이 아니여도 상관없기 때문에
테스트코드로 작성했다.

놀랍게도 이것의 실행결과는

이렇게 나온다. 결국 나는 객체로 만들지 않았는데,
스프링이 알아서 DI를 사용해주었다.ㅎㅎ;

정리하면,
스프링은 IOC라는 개념으로 빈(스프링 객체)으로 만들어준다.
그리고나면 빈들은 DI로 이용해서 의존성 주입을 할 수 있게되었다. 

참고로 @SpringbootTest는 스프링부트에서 만든 어노테이션이고, 이 어노테이션을 추가되는 순간부터,
비로소 스프링 빈들을 테스트에서 사용할 수 있게 해준다.
스프링 빈들을 사용하는 방법은 이 방법말고 많다.

그건

 

스프링과 bean

개요 스프링은 IOC (Injection Of Container) 를 이용해서 bean으로 관리하게 된다. 간단하게 @Service public class Study { } 라고 작성할 수 있습니다. 객체를 만들어 보자. @SpringBootTest class StudyTes..

b-programmer.tistory.com

여기에 정리해두었다.

근데 어째서 객체를 생성한적이 없는데 실행이 된것일까?
그것은 리플렉션이라는 것을 사용했기 때문이다.

 

리플렉션

스프링을 공부하다보면.. 빈을 주입하는 (객체를 만들어주는)... 것이 나온다. @Repository public class SchoolRepository { } @Service public class SchoolService { @Autowired SchoolRepository schoolRepos..

b-programmer.tistory.com

 

반응형

'SPRING START!' 카테고리의 다른 글

AOP  (0) 2021.08.25
DI 와 IOC  (0) 2021.08.14
이벤트 발생시키기!!  (0) 2021.01.12
스프링은 환경을 어떻게 조성할 수 있을까?(프로파일, 프로퍼티, 국제화)  (0) 2021.01.10
스프링과 bean  (0) 2021.01.07

댓글

Designed by JB FACTORY