*김영한 | 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의를 참조한 글입니다.
스프링 빈을 등록하는 방법에는 두 가지가 있다.
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
이번 시간에는 스프링 빈을 등록하는 두 가지 방법에 대해 배워볼 것이다.
1. 컴포넌트 스캔과 자동 의존관계 설정
이전시간에 서비스, 리포지토리, 테스트 등을 만들었고, 이번에는 화면을 붙이고 싶다.
그러기 위해선 Controller와 View가 필요하다.
멤버 컨트롤러는 멤버 서비스를 통해 회원가입을 하고 데이터를 조회할 수 있어야 한다.
=> 의존관계 형성 : 멤버 컨트롤러가 멤버 서비스에 의존
1-1. MemberController
'src - main - java - hellospring.hellospring - controller' 하위에 MemberController 클래스를 생성한다.
그다음 @Contorller를 작성한다.
아무 코드도 작성되어있지 않지만, 사실 무언가가 일어났다....
스프링이 처음 시작되면, '스프링 컨테이너'라는 통이 생긴다.
@Controller (Contorller annotation)가 작성되어있으면
자동적으로 MemberController 객체를 생성하여 스프링에 넣어두고 관리한다.
=> 스프링 컨테이너에서 스프링 빈이 관리된다.
작성할 전체 코드는 다음과 같다.
package hellospring.hellospring.controller;
import hellospring.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;
}
}
<코드 설명>
private final MemberService memberService;
// 멤버 컨트롤러에서 멤버 서비스를 아래와 같이 생성할 수도 있다.
private final MemberService memberService = new MemberService();
아래의 방식으로 멤버 서비스를 생성하면 발생하는 문제점 :
다른 여러 컨트롤러가 멤버 서비스를 사욯할 수 있고, 사용할 때마다 새로운 인스턴스를 생성한다.
멤버 서비스는 여러 인스턴스를 사용할 필요 없이
하나의 인스턴스만 생성하여 공용으로 사용해도 되는 인스턴스이다.
그래서 멤버 서비스를 스프링 컨테이너에 등록하고, 스프링 컨테이너에서 받아 쓸 수 있도록 관리하고자 한다.
=> @Service를 붙여 멤버 서비스를 컨테이너 빈에 등록하고,
@Autowired를 사용하여 스프링 컨테이너에 등록된 멤버 서비스를 주입받는다.
*DI(Dependency Injection) ; 의존성 주입
이처럼 외부에서 객체를 주입받는 것을 DI라고 한다.
스프링 컨테이너에서 객체가 관리되다가(스프링 컨테이너가 관리하는 객체를 빈;bean이라고 부른다), 필요할 때 객체를 주입한다.
*DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다.
- 필드 주입 : @Autowired를 필드에 작성 / 중간에 변경 불가
- setter 주입 : setter주입을 위해선 메서드가 public하게 노출되어 있어야함. 의존관계가 중간에 바뀌는 일은 드문데 이걸 굳이 public하게 열어놓을 필요가... x
- 생성자 주입 : 생성된 시점에 의존관계 주입을 하고 이후 변경하지 못하게 막아놓을 수 있음.
의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 가장 안전한 생성자 주입을 권장한다.
*스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다.(유일하게 하나만 등록해서 공유한다) 따라서 같은 스프링 빈이면 모두 같은 인스턴스다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.
실행시켜보면 MemberController, MemberService, MemoryMemberRepository가 모두 잘 연결된 것을 확인할 수 있다.
@Component이 붙으면 스프링은 해당 클래스의 객체를 자동으로 빈으로 등록한다.
@Controller, @Service, @Repository와 같은 애노테이션들은 내부적으로 @Component 애노테이션을 포함하기에 자동으로 스프링 빈으로 등록된다.
2. 자바 코드로 직접 스프링 빈 등록하기
여기서는 향후 메모리 리포지토리를 다른 리포지토리로 변경할 예정이므로,
컴포넌트 스캔 방식 대신에 자바 코드로 스프링 빈을 설정하겠다.
회원 서비스와 회원 리포지토리의 @Service, @Repository, @Autowired 애노테이션을 제거하고 진행한다.
*자바 코드 대신 XML로 설정하는 방식도 있지만 최근에는 잘 사용하지 않으므로 생략한다.
2-1. SpringConfig
'src - main - java - hellospring.hellospring - service' 패키지에 SpringConfig 클래스를 생성한다.
전체 코드는 다음과 같다.
package hellospring.hellospring.service;
import hellospring.hellospring.repository.MemberRepository;
import hellospring.hellospring.repository.MemoryMemberRepository;
import hellospring.hellospring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
<코드 설명>
@Configuration
: @Configuration 을 사용하면 이건 설정파일이야 ~ / Bean 등록할거야 ~ 란 의미이다.
@Bean
객체를 생성하고 반환하는 메서드에 @Bean을 붙여주면 스프링 컨테이너에 빈의 형태로 객체가 등록된다.
3. 정리
스프링 빈을 등록하는 방법에는 두 가지가 있다.
1. 컴포넌트 스캔과 자동 의존관계 설정
: 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다.
2. 자바 코드로 직접 스프링 빈 등록하기
: 정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야하는 경우 스프링 빈으로 등록한다.