-

[스프링부트 Step 11] - 컴포넌트 스캔과 자동 의존관계 설정 본문

백엔드 기술 정리/스프링 부트

[스프링부트 Step 11] - 컴포넌트 스캔과 자동 의존관계 설정

흣차 2022. 1. 1. 03:08
728x90
반응형

이번엔 스프링 빈을 직접 등록해보고 의존관계를 설정해볼 것입니다.

지난번엔 MemberService랑 MemberRepository를 만들고 서비스를 통해 회원을 가입할 수 있고 Repository에 저장이 되고 거기서 꺼내올 수 있는 로직을 만들었습니다.

또한 그것을 테스트하는 장치도 한 번 만들어 봤습니다.

그래서 이번엔, 화면에 어떻게 하면 이 데이터들을 출력하고 표기할 수 있을지, 제일 처음 배웠던 MVC 기억나시죠?

모델이랑 컨트롤러랑 View - Template이 필요합니다. 

따라서 회원가입을 하고 회원 가입된 결과를 시스템에 뿌려주어야 합니다.

이를 위해서는 MemberController가 필요합니다.

이 MemberController가 MemberService를 통해서 회원가입하고 이를 통해서 데이터를 조회할 수 있게 설계해야합니다.

이런 구조를 서로 의존관계가 있다고도 표현을 합니다.

그 작업을 스프링답게 한 번 해보겠습니다. 

자 MemberController부터 먼저 만들어봅시다.

늘 했던 것철엄 controller 패키지에 MemberController라는 클래스를 만들고 어노테이션을 걸었습니다.

스프링에서는 이처럼 Controller라는 어노테이션을 걸어 놓으면 스프링컨테이너라는 통이 하나 생깁니다.

거기에 이 컨트롤러 어노테이션이 있으면 MemberController 객체를 생성해서 스프링에 넣어둡니다.

그리고 스프링이 관리를 하게 됩니다.

이게 어떤 모양새냐면, 예전에 HelloController 다룰 때

스프링 컨테이너를 보면 안에 내장 톰캣 서버도 있고 HelloController에 녹샌 Bean 땅콩처럼 그려놓았죠.

Controller라는 어노테이션이 있으면 생성을 해서 자기가 관리를 합니다.

그래서 스프링과 관련된 컨트롤러 등의 기능이 동작할 수 있습니다.

그러면 이번엔 MemberController도 그 원리로 풀어서 해석해봅시다.

MemberController를 잘 활용하기 위해선 첫째로 MemberService를 가져다 와서 써야 합니다.

그런데 이전에 new로 생성해서도 쓸 수 있습니다.

하지만 스프링이 관리를 하게 되면 다 스프링 컨테이너에 등록하고 스프링 컨테이너에서 받아 쓰도록 바꾸어야 합니다.

왜냐하면 new로 해서 어떤 문제가 생기나요?

다른 MemberController 뿐만 아니라 그 외의 컨트롤러들이 MemberService를 가져다 쓸 때 문제가 발생합니다.

예를 들어 주문 컨트롤러에서도 MemberService를 쓸 수 있고 회원가입에서도 MemberService를 쓸 수 있을 것입니다.

회원은 여러 군데에서 쓰일 수 있으니까요.

그런데 막상 이 MemberSerivce를 들어가 보면 우리가 만든게 중복 회원 조회와 전체 회원 조회 등 딱히 MemberService의 모든 기능을 쓸 필요가 없습니다.

쉽게 생각해보면 하나의 서비스를 등록해놓고 공용으로 다같이 쓰면 훨씬 더 절약할 수 있지 않을까요?

자 그래서 스프링 컨테이너에 등록을 하고 써봅시다.

이때 등록을 하는건 한 가지만 등록이 됩니다.

자 그래서 어떻게 해볼거냐면 memberService를 Alt + Shift + Enter를 눌러서 Constructor를 추가합니다.

그리고 여기에

@Autowired라는 어노테이션을 걸어주면 이 MemberService를 스프링이 스프링컨테이너에 있는 MemberService를 찾아서 가져온 뒤 연결을 시켜줍니다.

그런데 스프링 입장에서 MemberService를 찾는다 하더라도 우리가 만든 memberService는 단순한 자바 클래스일 뿐이지 이게 우리가 찾던 memberService인지 모를 수가 있습니다.

MemberController 입장에서야 어노테이션인 Controller어노테이션을 보고 아 내가 관리하는 애구나 할 수 있는데 MemberService는 스프링 입장에서는 알 길이 없습니다.

그래서 스프링한테 MemberService가 Service라는 것을 알려주기 위해 규칙이 하나 있습니다.

자 그래서 어떻게 해주냐.

MemberService에 서비스라는 어노테이션을 달아주는 것입니다.

이렇게 해주면 스프링이 올라올 때 MemberService를 서비스네 하고 스프링컨테이너에 정상적으로 등록을 해줍니다.

그리고 Repository도 가보겠습니다.

Repository도 어노테이션으로 @Repository 라고 걸면 스프링 입장에서 '어 Repository네' 하고 똑같이 스프링 컨테이너에 등록하게 됩니다.

이게 되게 정형화된 패턴입니다.

컨트롤러를 통해서 외부 요청을 받고 서비스에서 비즈니스 로직을 만들고 Repository에서 데이터를 저장하는 이런 정형화된 패턴을 스프링은 가지고 있습니다.

이를 통해 스프링에 뜰 때 이 컨트롤러, 서비스, 레포지토리를 쫙 가지고 올라옵니다.

그리고 컨트롤러부터 보면 

컨트롤러랑 서비스를 연결시켜주어야 합니다.

자 그래서 이 연결은 Autowired를 쓰면 손쉽게 해결 가능했습니다.

생성자에서 이렇게 쓰면 MemberController가 생성이 될 때 스프링 Bean에 등록되어 있는 MemberService라는 객체를 넣어줍니다. 

 이게 바로 Dependency Injection 즉, 의존성 주입입니다.

 

뭔가 밖에서 넣어주는 느낌이 들죠? 

스프링이 넣어주기 때문입니다.

그래서

이렇게 MemberService에도 Autowired를 걸어주어, MemberService에 MemberRepository를 주입할 수 있게끔 만들 수 있습니다.

이 모든걸 스프링이 어노테이션만 보고 어라 서비스네! 하며 MemberService를 컨테이너에 등록함과 동시에 MemberSerervice라는 생성자를 호출합니다.

그런데 그때 Autowired가 있는걸 보고 아 너는 MemberRepository가 필요하구나 라고 해서 스프링 컨테이너에 있는 MemoryMemberRepository를 넣어줍니다.

그리고 나서야 이 그림이 완성이 됩니다.

정리를 해보겠습니다.

스프링 빈을 등록하는데는 원래 2가지 방법이 존재합니다.

  • 컴포넌트 스캔과 자동 의존관계 설정
  • 자바 코드로 직접 스프링 빈 등록하기

이렇게 있는데요.

저희가 했던게 위의 방식인 컴포넌트 스캔과 자동 의존관계 설정입니다.

자 왜 컴포넌트 스캔이냐면 MemberService안을 들어가 보겠습니다.

그리고 이 서비스 안을 들어가보겠습니다. (Ctrl + 좌클릭)

어라? 컴포넌트가 들어있네요.

이 서비스라는 어노테이션 내부에는 또 여러가지 어노테이션으로 이루어져 있다는걸 알 수 있습니다.

그 중에서 눈에 띄는건 컴포넌트입니다.

여기 들어와서 위로 올려서 보시면

This annotation serves as a specialization of @Component, allowing for implementation classes to be autodetected through classpath scanning.

이런 글귀가 주석으로 처리되어 있습니다.

해석해보면, 이 어노테이션은 특수한 컴포넌트로 이루어져있다고 보면 되겠어요. (영어 저질)

그리고 MemberController의 Controller 어노테이션을 살펴봐도

이렇게 컴포넌트 어노테이션이 붙어 있습니다.

Repository도 마찬가지로

이렇게 컴포넌트를 가지고 있네요.

자 스프링이 올라올 때 컴포넌트와 관련된 어노테이션이 있으면 스프링이 객체를 다 생성해서 스프링에 등록합니다. 그리고 Autowired는 연관관계라고 해서 터널로 연결을 해줍니다.

그럼 이 컴포넌트 어노테이션은 어떤 뜻을 가지고 있을까요?

이 컴포넌트는 스프링 빈에 자동 등록되는 역할을 합니다.

따라서 컴포넌트 어노테이션이 붙어 있으면 이 클래스는 자동으로 스프링 빈에 등록이 되는 것입니다.

따라서 컨트롤러나 서비스, 레포지토리가 컴포넌트를 가지고 있는 어노테이션인 

@Controller, @Service, @Repository를 가지고 있다는 것은 이것들이 스프링 빈으로 자동 등록되는 이유도 컴포넌트 스캔 때문입니다.

또한 스프링을 쓸 땐 웬만한 것들은 스프링 빈에 등록해서 써야 하기 때문에 얻는 이점이 많습니다.

(이 부분은 나중에 살펴봅니다.)

이후 컨트롤러가 서비스를, 서비스가 레포지토리를 쓸 수 있게 의존성 주입을 해줌으로써 의존성 주입을 통해 스프링에 등록된 것을 공용으로 사용하고 이를 컴포넌트 스캔과 자동 의존관계 설정이라고 할 수 있는 것입니다.

 

아 그리고 참고로 스프링 컨테이너에 스프링 빈을 등록할 때 기본으로 싱글톤으로 등록한다는 특징을 가지고 있습니다.

싱글톤이라는 것은 음.. 유일하게 하나를  등록하여 이를 공유한다고 보시면 되겠습니다.

그러니까 HelloController를 등록하려 한다면 그거 하나만, MemberService를 등록하려 한다면 그거 하나만 등록한다는 것을 싱글톤이라고 부릅니다.

따라서 같은 스프링 빈이면 모두 같은 인스턴스가 됩니다. 

웬만해선 거의 다 싱글톤으로 쓰고 있고 특별한 경우에는 변수를 줘서 빈에 등록할 수 있지만 기본적으로 싱글톤으로 한다는 것을 꼭 알고 있음 좋겠습니다.

 

728x90
반응형
Comments