6장에서는 스프링 빈이 무엇인지, 어떻게 등록하는지 알아보겠습니다.
공부 자료는 인프런 김영한 강사님의 스프링 입문편을 들었습니다.
https://inf.run/Jk5T
스프링 빈이란 ?
스프링 빈이란, 스프링 컨테이너가 관리하는 자바 객체입니다. 코드에서 new() 키워드를 통해 다양한 객체를 만들어 낼 수 있지만, 이 모든 객체가 스프링 컨테이너가 관리하지 않기 때문에 모든 객체가 스프링 빈은 아닙니다. 사용할 객체를 스프링 빈으로 등록해야지 관리하기 용이하고 편리하기 때문에 빈에 대해 이해하고, 활용하는 것이 매우 중요합니다.
스프링 빈을 등록하는 방법은 2가지가 있습니다. 스프링 빈을 등록하는 2가지 방법과 각각의 장단점에 대해서 알아보겠습니다.
컴포넌트 스캔 활용
첫 번째로 컴포넌트 스캔을 활용하여 자바 객체를 스프링 빈으로 등록하는 방법이 있습니다. 우선 요청에 대한 처리를 하기 위해서는 컨트롤러가 필요합니다. MemberController 를 생성해주고 @Controller 어노테이션을 상단에 붙여줍니다. 이 어노테이션을 통해 스프링 컨테이너가 생성될 때, MemberController 객체를 생성해서 스프링에 넣어둡니다. 그 후에는 컨테이너가 직접 MemberController 객체를 관리합니다. 이렇게 관련된 어노테이션을 컨테이너가 찾아 스프링 빈으로 등록하는 방법을 컴포넌트 스캔이라고 합니다.
컴포넌트 스캔에서는 편리하게 @Autowired 어노테이션을 사용하여 스프링 빈 객체들의 관계를 연결할 수 있습니다. 이와 같이 객체들의 의존관계를 외부에서 넣어주는 방법을 DI 의존성 주입이라고 합니다. 보통은 생성자 단계에서 많이 작성합니다.
MemberController 객체가 MemberService 객체와 외존관계가 있으므로 MemberService 객체 또한 스프링 빈으로 등록해야 합니다.
MemberController
package com.example.demo.controller;
import com.example.demo.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;
}
}
아래 코드와 같이, MemberService 또한 @Service 어노테이션을 통해, 스프링 빈으로 등록할 수 있습니다. 사실 스프링 빈은 @Component 어노테이션을 통해 등록합니다. @Controller, @Service, @Repository 어노테이션 모두 각각의 코드로 보면 안에 @Component 어노테이션이 등록되어 있음을 볼 수 있습니다. 단지 개발자가 사용하기 편하게 확장시켜 준 어노테이션입니다.
MemberService 역시 MemoryMemberRepository 객체와 의존관계가 맺어져 있기 때문에, @Autowired 로 두 객체를 연결한 뒤, MemoryMemberRepository 객체를 스프링 빈으로 등록해야 합니다.
MemberService
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
.
..
...
MemoryMemberRepository 객체를 @Repository 어노테이션을 통해 스프링 빈으로 등록했다면, 컨테이너가 생성될 때, 스프링 빈으로 등록한 3가지 객체를 모두 관리하고 연결해 사용합니다.
MemoryMemberRepository
@Repository
public class MemoryMemberRepository implements MemberRepository{ //멤버레포지토리를 구현하기로 한 클래스는 반드시 모든 메소드를 구현해야한다.
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
.
..
...
이렇게 어노테이션을 활용한 컴포넌트 스캔 방법을 통해 스프링 빈을 등록할 수 있습니다. 매우 간편하고 실무에서 주로 정형화 되는 컨트롤러, 서비스, 리포지토리에 대한 코드는 컴포넌트 스캔을 사용합니다. 그러나 같은 패키지 내에 있는 객체에 대해서 어노테이션을 생성해야지만 컴포넌트 스캔이 가능하기 때문에 클래스 구조를 잘 관리해야 합니다. 또한 @Autowired 통한 DI는 스프링 빈으로 등록된 객체들만 가능하다는 점도 주의해야 합니다.
직접 스프링 빈 등록
다음으로는 컴포넌트 스캔을 활용하지 않고 직접 자바 클래스를 구현하여 스프링 빈을 등록하는 방법입니다. 우선 앞서 실습한 서비스와 리포지토리의 @Service, @Repository, @Autowired 어노테이션을 모두 지워줍니다. 그 후 스프링 빈 설정 자바 파일 SpringConfig 파일을 생성합니다. main method 와 같은 패키지 내에서 생성해야합니다.
package com.example.demo;
import com.example.demo.repository.MemberRepository;
import com.example.demo.repository.MemoryMemberRepository;
import com.example.demo.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 어노테이션을 통해 스프링 빈 설정 클래스임을 알립니다.
- @Bean 어노테이션을 통해 해당 클래스를 스프링 빈으로 설정하겠다는 표시를 합니다.
- 빈으로 설정할 객체들의 생성자를 작성합니다. MemberService 는 MemoryMemberRepository 객체와 관계가 있으므로 생성할 때 관계를 맺어줍니다.
이렇게 직접 자바 설정 파일을 만든 후, @Bean 어노테이션을 통해 객체들을 스프링 빈으로 등록해보았습니다. 이 때 앞서 작성한 컨트롤러에 대한 코드는 수정하지 않습니다. 이렇게 직접 스프링 빈으로 등록하게 된다면, 정형화 되지 않거나 구현체 클래스를 상황에 맞게 변경할 수 있습니다. 앞선 예제의 요구사항에서 데이터 저장소에 대해서는 아직 정하지 않았다고 가정하였습니다. 때문에 리포지토리를 인터페이스로 선언했으며, 이를 MemoryMemberRepository 가 구현하는 방식으로 구현하였습니다. 이렇게 직접 리포지토리를 스프링 빈으로 등록하게 된다면 후에 데이터 저장소가 정해졌을 때 매우 간편하게 리포지토리를 변경할 수 있습니다. 이에 대해서는 후에 다시 포스팅하겠습니다.
현재까지 스프링 빈으로 등록한 객체들의 의존관계는 다음과 같습니다. 컨테이너가 이 3가지 객체들을 직접 관리합니다.
'개인 공부 > Spring' 카테고리의 다른 글
[Spring] #8 JPA 동작 원리 (0) | 2022.04.16 |
---|---|
[Spring] #7 JPA의 필요성 (0) | 2022.04.15 |
[Spring] #5 회원 서비스 구현 (0) | 2022.01.19 |
[Spring] #4 회원 리포지토리 테스트 케이스 작성 (0) | 2022.01.14 |
[Spring] #3 회원 도메인과 리포지토리 구현 (0) | 2022.01.12 |