14. 컴포넌트 스캔과 자동 의존관계 설정

이제 우리가 만든것을 화면에 붙이고 싶다. 그럼 컨트롤러와 뷰 템플릿이 필요하다.

회원가입하고 회원가입된것을 html로 뿌려주는 것들을 할거다.

이런걸 하려면 멤버 컨트롤러를 만들어야하는데, 이 멤버컨트롤러가, 멤버서비스를 통해서 회원가입하고, 멤버서비스를 통해서 데이터를 조회할 수 있어야 한다.

이거를 서로 의존관계가 있다고 한다. (멤버 컨트롤러가 멤버 서비스를 의존한다고 표현한다.)

이 작업을 스프링스럽게 해보자.

우선 멤버 컨트롤러를 만든다.

이렇게만 하면, 내용은 없지만

스프링이 처음 실행될때, 스프링 컨테이너라는 통이 생기는데, 거기에 @Controller 애노테이션이 붙으면

이 멤버 컨트롤러를 객체로 생성해서 스프링에 넣어두고 스프링이 관리를 한다.

우리가 앞시간에 실습했던 HelloController이거도 스프링과 관련되있어서 동작이 된것이다.

그림에서 @Controller라는 애노테이션을 보고 스프링이 뜰때 HelloController라는 객체를 생성해서 들고있는다.

이거를 '스프링 컨테이너에서 스프링 빈이 관리 된다' 라고 표현함

그림에서도 스프링 컨테이너 안에 helloController (마치 녹색 땅콩(빈)처럼 그림이 그려져있음)를 생성해놓고 관리를 한다. 그래서 스프링과 관련된 컨트롤러가 동작하는 것이다.

멤버 컨트롤러또한 스프링에서 관리가 된다. 멤버 컨트롤러에서도 멤버서비스를 가져다 써야하는데, 위처럼 new로 생성해서 쓸 수도 있는데, 이제 스프링이 관리하게 되면, 이제 다 스프링 컨테이너에 등록하고, 스프링 컨테이너로부터 받아서 쓰도록 바꿔야한다.

왜냐면 위처럼 new라고 하면 무슨문제가 생기냐면, 멤버컨트롤러 외에도 다른 여러 컨트롤러들이 멤버서비스를 가져다 쓸거다. 그때마다 new로 객체를 여러개 생성하면 꼬이게 된다.

그리고 멤버서비스 또한 구현된 기능이 별로없기때문에 굳이 여러개의 객체로 만들기 보다 하나를 만들고 공유하는게 좋다.

그래서 new로 객체를 생성하는 것 보다는 스프링 컨테이너에 등록하고 쓰면된다. 스프링 컨테이너에는 하나만 등록이 된다. 그외에 여러 부가적인 효과도 볼 수 있는데 뒤에 설명한다.

그림처럼 객체를 생성하지않고 생성자를 만든다. 그리고 @Autowired 애노테이션을 붙인다.

스프링이 뜰때, 이 멤버컨트롤러가 생성이 된다. 그러면 이 생성자를 호출하게 되는데, 생성자에 @Autowired가 붙어있으면, 스프링이 이 멤버서비스를 스프링 컨테이너에 있는 멤버서비스를 가져다가 연결시켜 준다. (그래서 wired라고 되어있다)

근데 그림에서 빨간줄뜨는거보니 뭐가안되는것같다(인텔리제이에서 빨간줄 제공)

멤버서비스를 찾을수 없다고 나온다.

@Autowired로 하면 스프링 컨테이너에서 멤버서비스를 가져온다고 했는데,

멤버서비스는 그냥 순수한 자바 클래스다. 스프링이 얘를 알 수 있는 방법이 없다.

멤버컨트롤러는 @Controller라는 애노테이션을 달았기 때문에 스프링이 뜰때 애노테이션보고 `아 얘는 내가 관리하는 얘니까 생성을 해야곘구나!` 이런 규칙이 있는데 멤버서비스는 그냥 순수한 자바 코드다. 그래서 아무것도 안된다.

그럼 어떻게 해야할까?

이렇게 @Service 애노테이션을 달아준다. @Service라고 하면 스프링이 올라올 때 스프링이 @Service 애노테이션과 멤버서비스 클래스를보고 `어? 얘는 서비스네?` 하고 스프링이 스프링 컨테이너에다가 멤버서비스를 딱 등록해준다.

그리고 리포지토리도 구현체에서 @Repository 애노테이션을 달아줘야한다.

정형화된 패턴이다. Controller - Service - Repository

컨트롤러를 통해서 외부 요청을 받고, 서비스에서 비즈니스 로직을 만들고, 리포지토리에서 데이터를 저장하는게 정형화된 패턴이다.

이렇게 애노테이션을 달면 스프링 컨테이너에 다 등록이 된다.

먼저 Controller에서 Service를 연결 시켜주기 위해 @Autowired를 생성자위에 씀.

멤버컨트롤러가 생성될때, 스프링 빈에 등록되어있는 멤버서비스 객체를 넣어준다. (이게 바로 Dependency Injection 이다. 의존성을 주입시켜준다는 의미)

멤버서비스도 멤버리포지토리가 필요하다.

스프링이 멤버서비스를 생성할때 @Service를 보고 스프링 컨테이너에 등록하면서 생성자를 호출한다. 이때 @Autowired가 있으면 `아 너는 멤버리포지토리가 필요하구나`라고 생각하고 스프링 컨테이너에 멤버리포지토리를 딱 넣어준다.

이렇게 애노테이션을 다 적절히넣어주고 메인메서드를 실행시키면

잘 작동한다. 스프링이 컨테이너를 만들때 문제없이 잘 됬다는 의미다.

스프링 빈 등록하는 방법 2가지

1. 컴포넌트 스캔과 자동 의존관계 설정

2. 자바 코드로 직접 스프링 빈 등록하기

위처럼 @Controller, @Service, @Repository 애노테이션은 모두 @Component 애노테이션을 가지고있다.

이렇게 애노테이션을 달아서 스프링 빈을 등록하는 방식이 컴포넌트 스캔방식이다.

자바 코드로 직접 스프링 빈에 등록하는 방법도있는데, 나중에 하자.

이 2가지 방식은 모두 잘 알고 있어야 함.

이 컴포넌트 스캔이 아무데서나 되는가? 그렇지는 않다. 위그림처럼 우리는 HelloSpringApplication이 있는 패키지 안에서만 스프링이 이 패키지 하위를 뒤져가면서 컴포넌트 스캔을 해준거고,

이 패키지가 아닌 곳에서는 스프링 빈으로 컴포넌트 스캔하지 않는다. 그래서 Demo클래스는 스프링 빈으로 등록되지 않는다. (물론 다른 설정을 통해 등록할 수 있는 방법은 있지만, 기본적으로 스캔의 대상이 아님)

SpringBootApplication 애노테이션 내부를 들어가보면 @ComponentScan이 있다. 이걸 통해서 스프링이 등록해주는 거다.

참고 : 스프링 컨테이너에 스프링 빈 등록시 기본적으로 '싱글톤' 으로 등록한다. 싱글톤이란, 유일하게 하나만 등록한다. 두개를 등록하지 않는다. HelloController면, HelloController하나만, MemberService면 MemberService하나만, MemberRepository면 MemberRepository하나만 등록하는 거다. 2개 등록하지 않는다. 유일하게 하나만 등록해서 공유 한다.

예를들어 멤버서비스말고 주문서비스가 있을때 얘 또한 멤버 리포지토리를 autowired로 하면 똑같은 인스턴스를 넣어준다. 이렇게하면 메모리도 절약되고 좋다.

물론 설정으로 싱글톤이 아니게 설정할 수있다. autowire로 하고 다른 인스턴스를 주입하는 방법도있기는 있다. 거의 대부분은 싱글톤을 쓰지만 정말 특수한 케이스에 싱글톤이 아니게 설정한다.

 

 

출처 : 인프런의 김영한 선생님 강의를 정리한 글입니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

댓글

Designed by JB FACTORY