이 글은 인프런에서 김영한님의 "스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술"을 수강 후 개인적으로 공부한 내용을 정리한 게시글입니다. 잘못된 점이나 부족한 부분이 있다면 언제든 지적 부탁드립니다
스프링 빈을 등록하는 2가지 방법
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
* 스프링 컨테이너 : 자바 객체의 생명 주기를 관리하며, 생성된 자바 객체들에게 추가적인 기능을 제공하는 역할.
여기서 말하는 자바 객체를 스프링에서는 빈(Bean)이라고 함.
1. 컴포넌트 스캔과 자동 의존관계 설정
: 회원 컨트롤러가 회원 서비스와 회원 리포지토리를 사용할 수 있게 의존관계를 준비하자!
컨트롤러 : 외부 요청을 받음
리포지토리 : 데이터 저장
서비스 : 비즈니스 로직을 만듦
그동안 작업한 로직을 화면으로 나타내기 위해서 컨트롤러를 작성해야 한다. 클라이언트의 요청을 받은 컨트롤러는 서비스를 통해 view를 제공한다. 즉, 회원 서비스를 사용하여 회원가입, 데이터 조회 등을 실시한다.
컨트롤러의 동작이 서비스에 의존하고, 우리는 이를 의존관계가 있다!라고 한다.
> controller 아래 MemberController 파일 생성 후 작성
package hello.hellospring.controller;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
@Controller를 사용해 MemberController라는 컨트롤러를 생성하였다.
@Controller가 있다면 스프링은 스프링 컨테이너에 MemberController라는 객체를 생성, 이 컨트롤러를 컨테이너 안에서 관리한다.
private final MemberService memberService = new MemberService(); 와 같이 new를 사용해 직접 MemberService 객체를 생성할 수도 있지만, 다른 컨트롤러가 회원 서비스를 사용할 때마다 회원 서비스 객체가 중복되어 생성될 것이고, 이때 컨트롤러는 굳이 다른 회원 서비스를 각각 생성하여 사용할 필요가 없다.
즉 회원 서비스는 한 번만 생성되어 생성된 하나의 회원 서비스 인스턴스를 각각의 컨트롤러들이 공유하는 것이 좋다. 등록된 하나의 회원 서비스를 컨테이너로부터 받아 사용해야 한다.
그래서 @Autowired를 사용한 것이다.
스프링은 @Controller로 MemerServiceController를 스프링 컨테이너에 등록, 생성자를 호출하게 된다. 생성자에 @Autowired이 있다면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI(Dependency Injection), 의존성 주입이라고 한다다. 이전 강의에서는 개발자가 직접 DI를 주입했고, 여기서는 @Autowired에 의해 스프링이 주입해 준다.
실행하면 에러가 뜬다 (멤버 서비스를 찾을 수 없음)
-> 이유 : 컨트롤러는 컨테이너에 등록되었지만 아직 회원 서비스는 컨테이너에 등록되지 않았기 때문!
MemberService는 아직 단순한 자바 코드일 뿐으로, 아직 스프링이 이를 인식하고 컨테이너에 스프링 빈으로 등록할 수 없다. memberController는 @Controller를 통해 컨테이너에 등록되었지만 memberService는 스프링 빈으로 컨테이너에 등록되지 않았기 때문에 의존성 주입이 되지 않은 상태이다.
> 해결 과정
- MemberService에 가서 @Service를 추가해준다.
- MemoryMemberRepository에 가서 @Repository를 추가해준다.
: 컨트롤러를 생성할 때 @Controller로 스프링에 알려준 것과 같이, MemberService와 MemoryMemberRepository 또한 각각 @Service, @Repository로 스프링 컨테이너에 등록해준다.
# 컴포넌트 스캔 원리
- @Component : 애노테이션이 있으면 스프링 빈으로 자동 등록된다
- @Controller : 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.
@Component 를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
- @Controller
- @Service
- @Repository
각각의 클래스는 @Component를 포함하기 때문에 @Component로 대체할 수 있다.
*스프링이 올라올 때 위와 같은 컴포넌트 관련 애노테이션이 존재한다면 스프링이 객체를 생성, 컨테이너에 스프링 빈으로 등록한다.
*연결 -> 의존성 주입하기
> MemberService 생성자에 @Autowired 코드 추가
: 생성자에 @Autowired 를 사용하면 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입한다.
(생성자가 1개만 있으면 @Autowired 는 생략할 수 있다)
: MemberService가 @Service를 통해 스프링 빈으로 등록될 때 생성자를 호출, 이때 @Autowired가 있으면 @Repository를 통해 컨테이너에 등록된 리포지토리 객체를 의존성 주입한다.
@SpringBootApplication을 실행하면 속해있는 패키지 내의 @Controller, @Service, @Repository를 통해 각각이 컨테이너에 등록되고, @Autowired를 통해 의존관계를 갖게 된다.
참고로 스프링은 스프링 컨테이너에 스프링 빈 등록 시 중복되지 않게 유일하게 하나의 객체만 싱글톤으로 등록합니다. 예를 들어 따로 설정을 하는 경우가 아니라면 다른 컨트롤러(또는 서비스)에서 사용하는 리포지토리는 같은 리포지토리 인스턴스를 사용합니다.
1. 자바 코드로 직접 스프링 빈 등록하기
> 회원 서비스와 회원 리포지토리의 @Service, @Repository, @Autowired 애노테이션을 제거하고 진행한다.
> MemberController는 그대로
컨트롤러는 컴포넌트 스캔 방식으로 작동한다.
: @Controller로 스프링 컨테이너에 등록, @Autowired로 스프링 빈에 등록된 객체와 연결
> hello.hellospring 아래 SpringConfig.java 생성
클래스명 앞에 @Configuration을 등록하면 스프링이 설정 파일임을 인식, 컨테이너에 스프링 빈을 등록할 준비를 한다.
@Bean을 사용하여 각각 memberService메서드와 memberRepository 메서드를 스프링 빈에 등록한다. memberService메서드를 실행하면 객체를 생성 후 반환해야하는데, 매개변수로 memberRepository 객체가 필요하므로 @Bean으로 컨테이너에 등록된 memberRepositroy를 가져온다(@Autowired 역할).
# 정리
의존성 주입 DI 에는 3가지 방법이 있다.
- 생성자 주입 : 위에서 살펴본 것처럼 new를 사용하여 생성자를 호출할 때 DI를 호출하기
- 필드 주입 : 생성자 없이 @Autowired로 DI를 주입하기
- setter 주입 : setter에 @Autowired로 연결하기
* 애플리케이션 조립(스프링 컨테이너 올라가고 세팅이 되는 시점)에 생성자를 한번만 호출하여 컨테이너에 스프링 빈을 등록하고, 의존관계가 실행중에 동적으로 변하는 경우는 없으므로 생성자 주입을 권장한다.
* 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.
* @Autowired 를 통한 DI는 helloConroller , memberService 등과 같이 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.
출처
인프런 김영한님 스프링 입문 - 컴포넌트 스캔과 자동 의존관계 설정
인프런 김영한님 스프링 입문 - 자바 코드로 직접 스프링 빈 등록하기
'Server > Spring boot' 카테고리의 다른 글
[Spring boot] Error : cannot deserialize from Object value (0) | 2022.05.18 |
---|---|
[스프링] 인프런 스프링 입문 #회원 관리 예제 - 웹 MVC 개발 (0) | 2022.01.30 |
[스프링] 인프런 스프링 입문 #회원 관리 예제 - 백엔드 개발 #2 (0) | 2022.01.19 |
[스프링] 인프런 스프링 입문 #회원 관리 예제 - 백엔드 개발 #1 (0) | 2022.01.18 |
[스프링] 인프런 스프링 입문 #스프링 웹개발 기초 (0) | 2022.01.18 |