이제 화면을 구축해야 하는데, 그러려면 멤버 컨트롤러를 만들어야 한다.
멤버 컨트롤러는 멤버 서비스를 통해서 회원가입하고, 데이터를 조회할 수 있어야 한다.
-> 서로 의존관계가 있다.
우선 src - main - java - hellospring - controller에 MemberController라는 자바 클래스를 하나 생성하였다.
그리고 @Controller를 작성하여 위 사진과 같은 코드를 생성해 놓았다.
이 상태에서는 기능은 아무것도 없지만,
스프링이 처음에 뜰 때 '스프링 컨테이너'라는 스프링 통이 생기는데
이 @Controller이 있으면
그 스프링 통에 MemberController 객체를 생성해서 넣어두고 관리를 한다.
@Controller가 있으면
그림에서 보이는 이 스프링 컨테이너에 helloController가 들어가서 관리되고 있는 것처럼 관리를 해주고, 스프링과 관련된 컨트롤러의 기능들이 동작을 하는 것이다.
private final MemberService memberService = new MemberService();
memberService를 가져다 써야하므로 new로 이렇게 생성을 해줄 수 있다.
그런데 이렇게 new로 생성을 하게 되면,
memberController말고 다른 여러 컨트롤러(ex: 주문 컨트롤러 등)들도 memberService를 가져다 쓸 수 있게 된다.
근데 memberService를 들어가보면, 그다지 별 기능이 없다.
여러 개를 생성할 필요 없이 하나만 생성해놓고 공유해서 쓰면 된다.
따라서 new로 생성하는 방법보다는 더 나은 방법이 있다.
스프링 컨테이너에 등록을 해놓고 쓰는 방법이다.
연결을 해주는 방법은 option + enter로 생성자를 자동작성해주면 된다.
그리고 @Autowired를 해주는데,
이는 memberService와
스프링 컨테이너에 있는 memberService를 가져다가 연결을 해준다.
이 상태에서 run을 하려고 보면, 에러가 나면서 돌아가지 않는다.
MemberService 클래스를 보자.
이 클래스는 그냥 순수한 자바 클래스이다.
spring이 이 클래스가 무엇인지 알 수 있는 방법이 없다.
따라서 @Service 를 해주어야 하는 것이다.
이렇게 @Service를 해주고 나서 생각해보자.
@Service를 해주면, 스프링이 어? 서비스네? 하면서 스프링 컨테이너에 MemberService를 등록해준다.
MemberService 클래스엔 @Service,
memberController 클래스엔 @Controller,
이런 정형화된 패턴으로
MemoryMemberRepository 클래스에도 @Repository를 해준다.
controller을 통해서 외부 요청을 받고, service에서 비즈니스 로직을 만들고, repository에서 데이터를 저장하는 패턴이다.
이제, controller와 service를 연결시켜줘야 한다.
아까 해주었던 MemberController의 @Autowired가 이 기능을 해 주는 것이다.
MemberController가 생성 될 때,
스프링 빈에 등록되어 있는 MemberService 객체를 가져다가 넣어준다.
이 과정들이 바로 Dependency Injection(DI) : 의존성 주입 인 것이다.
MemberService 클래스에 가서 보면,
MemberService는 MemberRepository를 필요로 하기 때문에
MemberService에서도 @Autowired를 해주면,
아까와 똑같이 스프링에서 알아채고 컨테이너에 있는 MemberRepository를 넣어준다.
MemoryMemberRepository가 구현체로 있기 때문에 MemoryMemberRepository를 Service에 주입을 해준다.
이렇게 모두 의존 관계를 주입해 준 후,
main method를 run 해보면 제대로 동작되는 것을 볼 수 있다.--> Spring이 컨테이너를 만들 때 문제 없이 잘 되었다는 것이다.
하지만 지금은 회원 컨트롤러와 관련된 어떤 기능도 존재하진 않는 상태이다.
스프링 빈을 등록하는 데에는 두 가지 방법이 있다.
1. 컴포넌트 스캔과 자동 의존관계 설정
2. 자바 코드로 직접 스프링 빈 등록하기
위에서 하였던 방식은 1번째 방식이다.
왜 컴포넌트 스캔 방식이라고 하냐면,
원래는 MemberService에 @Service가 아니라 @Component를 해줘야 한다.
근데 왜 @Service를 해주느냐,
command + b를 통해 service 안으로 들어와 보면
Component가 이미 등록이 돼 있는 것을 볼 수 있다.
Controller, Repository도 마찬가지로 Component가 등록이 되어 있다.
그래서 결론적으론 Component annotation이 되어 있으면
컨테이너가 등록을 해주고,
AutoWired가 이들을 연결해 주는 것이다.
==> 이것이 바로 컴포넌트 스캔과 자동 의존관계 설정이다.
사실 웬만한 것들은 모두 @Component를 이용해 스프링 빈으로 등록을 해놔야 한다고 생각하면 된다.
자세한 어떤 이점이 있는지는 더 뒷부분에서 진행하겠다.
그럼 질문이 하나 생길 수 있다.
아무데나 @Component를 해도 되는 것일까?
결론부터 말하면 안 된다.
HelloSpringApplication를 run 시키는 것이므로
hello.hellospring과 그 하위 패키지들만 @Component를 허용한다.
**참고) 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다. 싱글톤이라는 것은 유일하게 하나만 등록해서 공유한다는 뜻이다. 따라서 같은 스프링 빈이면 모두 같은 인스턴스이다. 설정으로 싱글톤이 아니게 설정할 수는 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.