컴포넌트 스캔과 자동 의존관계 설정
지금까지 우리는,
MemberService와 MemberRepository를 만들었다.
그리고, Member객체도 만들고, 서비스를 통해서 멤버가 가입할 수 있고, 리포지토리에 저장이 되고,
리포지토리에서 꺼내올수 있는 이러한 로직들을 만들었고,
테스트도 만들었었다.
이번시간에는,
화면을 붙이고 싶은데 그럴려면 먼저 컨트롤러와 view템플릿이 필요하다.
회원가입하고, 회원가입된 결과를 html로 뿌려주고, 이러한 것들을 하려고 한다.
그럴려면, 멤버 컨트롤러를 만들어야 하는데, 멤버 컨트롤러가 멤버서비스를 통해서 회원가입을 하고, 멤버서비스를 통해서 데이터를 조회할 수 있어야 한다.
이렇게 되는 것을 "서로 의존 관계가 있다." 라고 표현한다. (멤버컨트롤러가 멤버서비스를 의존한다.)
이 작업을 Spring스럽게 해보자.
먼저 멤버컨트롤러를 만들어보자.
이렇게 까지 작성해 놓으면,
기능은 아무것도 없지만 어떤 일이 벌어지냐면,
스프링이 처음에 뜰 때, SpringContainer가 생기는데,
@Controller 애너테이션이 있으면, MemberController객체를 생성해서 SpringContainer에 넣어둔다.
그리고 스프링이 관리를 한다.
이것을 "스프링 컨테이너에서 스프링 빈이 관리된다." 라고 한다.
그림으로 다시 확인해보면 이러하다.
@Controller라는 애너테이션이 있으면, 스프링이 뜰때,
스프링 컨테이너에 해당 컨트롤러 객체를 생성을 해서 관리한다.
다시 돌아와서,
그러면, MemberController가 memberservice를 가져다가 써야하는데,
이렇게 new로 생성해서 사용할 수도 있다.
하지만, 스프링이 관리를 하게 되면,
전부 스프링 컨테이너에 등록을 하게 되고, 스프링 컨테이너로부터 받아서 쓰도록 바꿔야 한다.
그 이유를 알아보자.
MemberController말고 다른 여러 컨트롤러들이 memberService를 가져다 쓸수있다.
예를 들면, 주문 컨트롤러에서도 memberService를 가져다 쓸 수도 있다.. 회원은 여러군대에서 사용되기 때문이다.
MemberService를 살펴보면, 기능 자체가,
여러개의 인스턴스를 생성할 필요가 없고, 하나만 생성해서 같이 공용으로 사용하면 될 것으로 예상된다.
그런데 객체를 new로 생성해서 사용하게 되면, 여러개의 MemberService객체가 생성되어 비효율 적이다.
그래서 공용으로 사용하려면 어떻게 해야하냐면,
스프링 컨테이너에 등록을 하고 사용해야 한다.
스프링 컨테이너에 등록을 하면, 딱 1개만 등록하게 된다.
이렇게 하면 방금 설명한 효과 외에도 굉장히 많은 부가적인 효과들이 있다. 이것들에 대해서는 뒤에서 좀더 알아볼 것이다.
이제, 연결을 해보자.
cmd+n을 눌러서 생성자로 연결하면 된다.
그리고 여기에 @Autowired라고 해주면,
어쨋든 MemberController가 @Controller애너테이션이 붙어있으므로, 스프링을 띄우면
스프링 컨테이너가 만들어지면서 거기에 MemberController를 생성한다고 했었다.
그러면, 그때, MemberController 내부에 있는 생성자를 호출하는데,
생성자에 @Autowired 애너테이션이 있으면,
이 코드의 memberService를 스프링이 스프링 컨테이너에 있는 memberService를 가져다가 연결을 시켜준다.
그런데, 지금 코드를 보면, 빨간 밑줄이 그어져 있다.
뭔가 잘 안되는 것같다.
일단 HelloSpringApplication을 run시켜보자.
MemberService could not be found 라는 것을 볼 수 있다.
무슨 이야기냐면,
@Autowired라고 하면, 스프링 컨테이너에서 memberService를 가져와서연결시켜준다고 했다.
그런데!!!
그림을 보자.
MemberController는 @Controller 애너테이션때문에, 스프링이 딱 뜰때, 스프링컨테이너에 등록이 된다.
그러면, MemberController는안에 @Autowired 애너테이션이 있으므로 스프링 컨테이너에서 관리하는 memberservice를 가져다가 스프링이 연결해주는데,
현재는 빨간 밑줄이 그어져 있는 것처럼, 연결이 안된다.
왜냐하면,
MemberService를 살펴보면,
MemberService는 그냥 순수한 Java클래스이다. 스프링이 이게 뭔지 알 수 있는 방법이 없다.
MemberController는 @Controller 애너테이션때문에 스프링이 뜰 때, 애너테이션을 보고 "아! 이건 내가 관리해야할 대상이구나" 라고 하고 스프링 컨테이너에 생성해서 등록해두는 규칙에따라 등록하는데,
MemberService는 순수한 Java코드이다. 그래서 아무것도 되지 않는다.
그러면 어떻게 해야할까?
MemberService에 @Service 애너테이션을 붙여주면 된다.
@Service애너테이션을 붙이면, 스프링이 "어? @Service네?" 라고 하고
스프링 컨테이너에 MemberService를 등록 해준다.
그리고 MemberRepository로 가보자.
그리고 MemberRpository구현체인 MemoryMemberRepository로 가서
@Repository 애너테이션을 작성해주면 된다.
@Controller - Controller,
@Service - Service,
@Repository - Repository
Controller 통해서 외부 요청을 받고,
Service통해서 비즈니스 로직을 만들고,
Repository에서 데이터를 저장하는.
이것은 굉장히 정형화된 패턴이다.
이렇게 해놓으면,
스프링이 뜰 때, @Controller, @Repository, @Service를 쫙 가지고 올라와서 스프링 컨테이너에 등록해 준다.
그리고 나서, 뭘 해주냐면,
Controller와 Service를 연결시켜 줘야 한다.
연결시켜줄 때, @Autowired를 쓰면 된다고 했었다.
생성자에 @Autowired를 쓰면,
MemberController가 생성이 될 때, 스프링빈에 등록되어 있는 MemberService 객체를 가져다가 넣어준다.
이게 바로 DI(Dependency Injection 의존성 주입)이다. 스프링이 딱 넣어주는 것이다.
이번에는 MemberService를 보자.
생성자에 @Autowired를 작성해 주었다.
그러면, MemberService는 MemberRepository가 필요한데,
@Autowired가 있으면,
MemberService를 스프링이 @Service를 보고 생성을 할 때,
스프링 컨테이너에 등록을 하면서, 생성자를 호출하면서 @Autowired가 있으면,
"아 MemberService는 MemberRepository가 필요하구나?"라고 하면서 스프링컨테이너에 있는 MemberRepository를 MemberService에 넣어준다.
지금 같은 경우에는 구현체로 MemoryMemberRepository가 있으므로 이 MemoryMemberRepository를 MemberService에 주입을 해준다.
그러면 이렇게 memberController, memberService, memberRepository가 연결이 완료된다.
이 상태에서 HelloSpringApplication을 실행해보자.
Tomcat started on port:8080도 잘 뜬것을 볼 수 있다.
즉, 스프링이 스프링 컨테이너를 만들때 문제없이 잘 되었다는 뜻이다.
지금은 MemberController 관련된 기능이 아무것도 없기 때문에,
연결하는 과정만 알아보았다.
정리를 해보자.
스프링 빈을 등록하는 방법은 2가지가 있다.
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
-컴포넌트 스캔 원리
우리가 위에서
@Controlle
@Service
@Repository
애너테이션을 통해 한 것이 컴포넌트 스캔 방식이다.
이것이 왜 컴포넌트 방식이냐면,
MemberService로 살펴보면, @Service 대신 사실은 @Componen라고 하면 된다.
"어? 나는 @Service 라고 했는데 왜 되는 거지?"
라고 생각 할 수 있다. @Service 애너테이션 내부를 살펴보자.
@Service 안을 보면,
@Component라는 애너테이션이 등록이 되어 있다.
그리고 @Contorller도 마찬가지이다.
@Controller 내부를 보면, @Component 애너테이션이 붙어있다.
그리고 @Repository도 마찬가지 일 것이다.
@Repository 내부도 살펴보면, @Component라고 붙어있다.
그래서, 원래 이름은 컴포넌트 스캔 이라고 한다.
스프링이 올라올 때,
@Component 와 관련된 애너테이션이 있으면,
그것들은 전부 객체를 하나씩 생성해서 스프링 컨테이너에 등록을 한다.
그리고 @Autowired는 등록이 되어 있는 것들을 연결해준다.
@Autowired 덕분에
MemberController가 memberService를 쓸 수 있게되고,
memberService가 memberRepository를 쓸 수 있게 되는 것이다.
이러한 방법이,
컴포넌트 스캔과 자동 의존관계 설정 이라는 것이다.
그리고, 두번째 방법은,
- 자바 코드로 직접 스프링 빈 등록하기 이다.
두가지 방법을 모두 알아야 한다.
스프링을 쓰면, 왠만한 것들을 스프링 빈으로 등록을 해서 써야한다.
그렇게 해야 얻는 이점이 많다. 이점들은 공부하면서 하나씩 알아갈 것이다.ex)AOP
이쯤에서 드는 궁굼증이 있는데,
"그러면 아무대나 @Component 가 있어도 되나요?"
예를 들어 이렇게 아무 패키지를 만들어서 클래스를 생성하고, @Service를 붙이면 될까?
기본적으로는 "안된다." 이다.
왜냐하면, 이게 어디서부터 되냐면,
지금 우리가 HelloSpringApplication을 실행시키는데,
hello.hellospiorng 패키지의 하위들은 스프링이 자동으로 전부 탐색해서 스프링빈으로 등록한다.
그런데, hello.hellospring 패키지와 동일하거나 하위패키지가 아닌 패키지들은
스프링빈으로 컴포넌트 스캔을 하지 않는다.
그래서 demo는 등록되지 않는다.(설정을 해주면 가능하지만, 기본적으로는 컴포넌트 스캔대상X)
hello.hellospiorng 패키지를 포함한 하위패키지만 컴포넌트 스캔 대상이다.
demo패키지는 다시 삭제하자.
참고로,
스프링은 스프링 컨테이너에 스프링 빈을 등록할 때,
기본으로 싱글톤으로 등록한다. (싱글톤이 뭐냐면, 유일하게 하나만 등록해서 공유한다는 뜻 ex 회원컨트롤러는1개만, 멤버서비스는 1개만 멤버리포지토리도1개만)
따라서 같은 스프링 빈이면 모두 같은 인스턴스이다.
설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤으로 사용한다.
다음시간에는 자바코드로 직접 스프링 빈을 등록해보도록 하겠다.
'Spring' 카테고리의 다른 글
스프링 입문 - 회원 웹 기능 - 홈 화면 추가 (0) | 2022.05.19 |
---|---|
스프링 입문 - 자바 코드로 직접 스프링 빈 등록하기 (0) | 2022.05.19 |
스프링 입문 - 회원 서비스 테스트 (0) | 2022.05.18 |
스프링 입문 - 회원 서비스 개발 (0) | 2022.05.17 |
스프링 입문 - 회원 리포지토리 테스트 케이스 작성 (0) | 2022.05.17 |
댓글
이 글 공유하기
다른 글
-
스프링 입문 - 회원 웹 기능 - 홈 화면 추가
스프링 입문 - 회원 웹 기능 - 홈 화면 추가
2022.05.19 -
스프링 입문 - 자바 코드로 직접 스프링 빈 등록하기
스프링 입문 - 자바 코드로 직접 스프링 빈 등록하기
2022.05.19 -
스프링 입문 - 회원 서비스 테스트
스프링 입문 - 회원 서비스 테스트
2022.05.18 -
스프링 입문 - 회원 서비스 개발
스프링 입문 - 회원 서비스 개발
2022.05.17