의존성이 주입되는 과정...

2023. 12. 27. 18:27
728x90

컨트롤러 클래스에 @Controller 애너테이션을 달아주면

 

Spring Container라는 스프링 통이 있는데, 

컨트롤러 객체를 생성해서 이 통에 넣어둔다. 그리고 스프링이 관리를 해준다. 

 

new ~(); 로 객체를 생성하면 ? 

다른 컨트롤러에서도 멤버 서비스를 받아서 쓸 수 있다........ 

그리고 사실 Service는 여러 개의 인스턴스를 생성할 필요가 없다..

이보다는 

스프링 컨테이너에 등록을 해주고 얘를 써주는 것이 좋다. 

어차피 스프링 컨테이너에 등록을 하면 딱 하나만 된다. (싱글톤 패턴)

 

 

ㅇㅋ 그럼 등록할게용

그러면 요렇게 표현할 수 있다. 

필드에서 new~ 로 생성해주는 것이 아니라, 생성자 안에 인자로 MemberService를 넣어주어 MemberController가 생성될 때 자동으로 MemberService가 생성되도록! 

그런데 여기서 @Autowired 애너테이션을 달아준다.

그러면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다.!!! (이것을 우리는 의존성 주입 DI라고 부른다)

 

잉 근데 연관된 객체라는 것을 어떻게 알지!!!?????

그래서 저기에 빨간줄이 뜨는 것.... MemberService에도 이게 바로 연관된 객체야!!! 라고 알려주기 위해 표시를 해주어야 한다. 

 

어떻게?

@Service 애너테이션을 통해 ㅎㅎ

오케이 달아줬더니 Controller의 빨간줄은 사라졌다. 

얘를 인식한다는 이야기...

 

근데 여기서도 @Autowired 달면 MemberRepository에 빨간줄이 뜬다. 

이친구도 인식할 수 있도록 애너테이션을 달아주자.

MemberRepository의 구현체인 MemoryMemberRepository로 가서 애너테이션을 달아주었다. 

얘는 레포지토리야~ 라고 @Repository를 달아준다.

 

 

전체적인 그림은 이렇게 된다.

스프링 컨테이너 안에 memberService와 memberRepository가 스프링 빈으로 등록이 된다. 

풀어서 말하면

MemberController의 객체를 생성할 때, 

MemberService 객체가 필요하다.

스프링에서 찾아서 쓰려면 이게 바로 그 객체야~~하도록 그에 알맞는 애너테이션을 달아주어야 한다. @Service 달아주고,

또, MemberService의 객체가 생성될 때에는 MemberRepository의 객체가 필요하다. 

이때 필요한 애너테이션이 @Repository. 달아주면 스프링 빈으로 등록이 되면서 찾아 쓸 수 있게 된다. 

 

이렇게 되면 직접 MemberService service = new MemberService(); 이런 식으로 직접 객체를 생성해주는 것이 아닌, 

외부에서 받아오도록 의존성을 주입해주게 되는 것이다. 

 

cf)

의존성이 주입되지 않은 버전을 살펴보면 확실하게 느낌이 온다.

@Controller
public class MemberController {
    private MemberService memberService;

    public MemberController() {
        this.memberService = new MemberService();
    }
}

만약, 이런식으로 MemberController의 생성자에서 MemberService 객체를 생성한다면

...

두 클래스가 강하게 결합되게 된다.

또한, 객체들 간의 관계가 아닌, 클래스 간의 관계가 맺어지게 된다. . . 

 

객체지향의 진짜 의미는 객체의 구현체가 어떤 것이든간에 같은 인터페이스를 구현했다면 인터페이스 타입으로 사용할 수 있어야 한다. 

그러나, 이렇게 클래스 간의 관계를 맺게된다면 어쩔 수 없이 특정 구현체를 생성자 안에서 생성해야 한다....

 

이해가 잘 안되어서 직접 만들어 보았다. 

그러면 MemberRepository 인터페이스를 상속받는 클래스를 두개 만드는 것이다.

1) MemoryMemberRepository implements MemberRepository

2) ExampleRepository implements MemberRepository

둘 다 MemberRepository를 상속받기 때문에 

만약 위의 의존성 주입 버전에서는 둘 다 MemberRepository의 구현체가 된다면 서비스 생성 시 들어가게 된다...(**다 형 성 **)

 

그러나, 의존성 주입하지 않은 버전이라면...?

@Service
public class MemberService {
    private final MemberRepository memberRepository;

    public MemberService() {
        this.memberRepository = new MemoryMemberRepository();
//      this.memberRepository = new ExampleRepository();
    }

서비스 클래스에서 바로 생성을 해야하기 때문에 "특정"한 인터페이스구현체를 직접 생성해주어야 한다. 

이렇게 되면 확장성이 훠어어얼씬 떨어진다...

아.. 이래서 의존성 주입을 하는구나!( 그리고 이런 의존성 주입 방법에는 여러가지가 있다... 더 공부해야 할 것! )

결합도를 낮추고,,, 유연성을 확보! 

 

 

스프링 프레임워크가 이것을 지원해준다..

스프링은 특정 위치부터 클래스를 탐색하고, 객체를 만들고, 이 객체들의 관계를 설정해준다. 그래서 스프링이 DI 컨테이너다.

그리고 이런 과정을 거치면 제어의 역전(IoC)가 일어난다. . 

어떤 객체를 사용할지에 대한 책임은 프레임워크가 하고, 결국 사용 시 수동적으로 주입받는 객체를 사용하게 된다.  

728x90

BELATED ARTICLES

more