스프링 빈을 등록하고, 의존관계 설정하기
- memberService랑 memberRepository 만든 걸 화면에 붙이고 싶어 → 컨트롤러랑 뷰템플릿이 필요하다.
- memberController가 memberService를 통해서 회원가입하고 조회할 수 있어야 한다. 이런 것을 의존관계가 있다고 표현한다.(memberController가 memberService를 의존)
따라서 회원 컨트롤러가 회원서비스와 회원 리포지토리를 사용하려면 의존관계가 있어야한다.
✔︎ @Controller 어노테이션이 붙으면 스프링 컨테이너가 스프링 뜰 때 멤버 컨트롤러 객체를 생성해서 스프링에 넣어놓고 관리한다.
→ 이를 컨테이너에서 스프링 빈이 관리된다라고 표현한다.
✔︎ 생성자에 @Autowired 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI(Dependency Injection), 의존성 주입이라고 한다.
- 생성자에 @Autowired 있으면 memberController가 생성이 될 때 스프링 빈에 등록되어 있는 memberService 객체를 가져다 넣어준다. ➡︎ DI (의존관계 주입)
- memberService는 memberRepository가 필요하다. memberService가 생성될 때 스프링이 @Service인 것을 확인하고 스프링 컨테이너에 등록을 하면서 생성자를 호출한다. 그런데 @Autowired가 있으니 memberRepository가 필요하구나 해서 스프링 컨테이너에 있는 memberRepository를 넣어준다. 그럼 연결 완료 !!
✔︎ 스프링을 쓰면 웬만한 건 다 스프링 빈으로 등록해서 써야 좋다.(왜인지는 나중에)
✔︎ 참고: 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다.(유일하게 하나만 등록해서 공유한다 (메모리 절약)) 따라서 같은 스프링 빈이면 모두 같은 인스턴스이다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.
스프링 빈을 등록하는 2가지 방법
(1번과 2번은 각각 장단점이 있다.)
1. 컴포넌트 스캔과 자동 의존관계 설정
✔︎ 컴포넌트 스캔 원리
- @Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다.
- @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.
- @Component 를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
- @Controller, @Service, @Repository
(타고 들어가면 @Component 있음)
- @Controller, @Service, @Repository
- 아무 곳에나 component 있어도 되나요?
→ 기본은 안됨. 어디서부터 되냐면 메인 실행하는 곳의 패키지(여기선 hello.hellospring)의 하위 패키지가 아니면 컴포넌트 스캔 대상이 아니다. 해당 패키지를 포함한 하위 패키지만!!!
2. 자바 코드로 직접 스프링 빈 등록하기
하나하나 직접 설정 파일에 등록한다.
회원 서비스와 회원 리포지토리의 @Service, @Repository, @Autowired 애노테이션을 제거하고 진행
- hello.hellospring에 SpringConfig 파일 만들고 안에 빈을 등록한다. (service랑 repository)
- 컨트롤러는 어쨌든 스프링이 관리하는 것이기 때문에 component 스캔에 올라간다. 따라서 autowired로 연결해주면 된다. (멤버 서비스 넣어주면 됨)
- 참고: 자바 코드로 설정하지 않고 XML로 설정하는 방식도 있지만 최근에는 잘 사용하지 않으므로 생략한다.
- 참고: DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다. 의존관계가 실행 중에 동적으로 변하는 경우(서버가 떠있는데 중간중간에 바꿔치기하는 거)는 거의(아예) 없으므로 생성자 주입을 권장한다. (아래처럼)
- 필드 주입(별로 안 좋음. 중간에 바꿀 수 있는 방법 아예 없다. )
- setter주입(setter를 통해서 주입된다. 생성은 생성대로 되고 setter는 나중에 호출이 돼서 들어온다. 단점은 누군가가 memberController를 호출했을 때 public으로 열려있어야 한다. 한번 세팅하고 나면 중간에 바꿀 일 없는데, public으로 노출이 되니까 중간에 잘못 바꾸면 문제 된다. 아무 개발자나 호출할 수 있게 열려있는 것.)
- 개발은 최대한 호출하지 않아야 할 메서드가 호출되면 안 된다. 조립 시점에 딱 생성자로 조립해놓고 끝내버려야 한다. 그럼 생성하는 시점에서 딱 넣고 다음에 변경 못하도록 막을 수 있다.
// 생성자 주입
// 생성자를 통해서 MemberService가 memberController에 주입이 된다.
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
- 참고: 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드(일반적으로 작성하는 컨트롤러, 서비스, 리포지토리 같은 것들)는 컴포넌트 스캔을 사용한다. 그리고 정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.(-> 예. 데이터 저장소가 선정되지 않았거나, 다른 저장소로 바꾸고 싶은데 기존 코드를 하나도 손대지 않고 바꿀 때 유용)
- 주의: @Autowired 를 통한 DI는 helloCotroller, memberService 등과 같이 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체(new로 작성한)에서는 동작하지 않는다. ( 스프링 컨테이너에 올라가는 것들만 동작 !!)
회원 관리 예제 - 웹 MVC 개발
✔︎ 컨트롤러가 정적파일보다 우선순위가 높다.
먼저 요청이 오면 스프링 컨테이너에서 관련 컨트롤러를 먼저 찾고 없으면 static 찾도록 되어있다 !!
(그래서 컨트롤러에 홈화면 추가 하면 index.html 무시되는 것임. )
참조
이 게시물은 인프런 > 김영한님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술의 강의를 토대로 작성한 게시물입니다.
'Web > Spring' 카테고리의 다른 글
AOP (0) | 2021.07.25 |
---|---|
스프링 DB 접근 기술 (0) | 2021.07.25 |
회원 관리 예제 - 백엔드 개발 (0) | 2021.07.25 |
스프링 웹 개발 기초(정적 컨텐츠, MVC와 템플릿 엔진, API) (0) | 2021.07.24 |
스프링 프로젝트 환경설정 (0) | 2021.07.20 |