[Spring Boot] 3. Spring Bean과 의존 관계
by Rev_스프링 빈
Spring에 의하여 생성되어 관리되는 자바 객체를 Bean이라고 한다.
스프링 컨테이너는 스프링 빈의 생명 주기를 관리하며, 생성된 스프링 빈들에게 추가적인 기능을 제공한다. IoC(제어의 역전)와 DI(의존성 주입)의 원리가 스프링 컨테이너에 적용된다.
현재 진행하는 예제에서 회원 컨트롤러가 회원 서비스와 회원 리포지토리를 사용할 수 있게 의존관계의 설정이 필요하다.
- IoC(제어의 역전)
객체의 생성 및 제어권을 사용자가 아닌 스프링에게 맡기는 것이다.
이전까지는 사용자가 new 연산을 통해 객체를 생성하고 메소드를 호출했지만 IoC가 적용된 경우에는 이런 객체의 생성과 사용자의 제어권을 스프링에게 넘긴다. 따라서 사용자가 직접 new를 통해 객체를 생성하지 않는다.
- DI(의존성 주입)
DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다.
스프링은 @Autowired 애노테이션을 통한 다양한 의존성 주입 방법을 제공한다. @Autowired은 spring에게 의존성을 주입하라는 지시자 역할로 쓰인다. 의존관계가 실행 중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.
Component Scan(컴포넌트 스캔)
@Component 어노테이션이 있으면 스프링 빈으로 자동 등록된다.
@Controller가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다. 스프링이 알아서 스프링 컨테이너에 빈을 등록한다. 이 외에도 @Service, @Repository, @Configuration 모두 @Component의 상속을 받고 있으므로 모두 컴포넌트 스캔의 대상이다.
@Controller: 스프링 MVC 컨트롤러
@Repository: 스프링 데이터 접근 계층
@Service: 개발자들이 핵심 비즈니스 계층을 인식하는데 도움
@Configuration: 스프링 설정 정보로 인식하고 스프링 빈이 싱글톤을 유지하도록 추가 처리
* 싱글톤: 실제로 생성되는 객체는 하나이고, 최조 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴
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 {
// 객체를 생성하지 말고 스프링 컨테이너에 생성을 해둔다.
// Autowired를 통해 객체의 생성과 제어권을 Spring한테 넘김
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
새로 MemberController.java를 생성해주었다.
이 프로젝트는 memberController --> memberService --> memberRepository의 구조로 이루어진다.
자바 코드로 직접 스프링 빈 등록
위처럼 컴포넌트 스캔을 사용하지 않고 직접 자바 코드를 생성하는 방법도 있다.
회원 서비스와 회원 리포지토리에 @Service, @Repository, @Autowired 어노테이션을 제거하고 진행한다.
전체 패키지에서 SpringConfig를 만들고 @Configuration과 @Bean을 사용해준다.
package hello.hellospring;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.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();
}
}
두 개의 연결된 빈을 생성한 것을 볼 수 있다.
장단점
이 두가지 방법의 장단점은 무엇일까?
실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다.
그리고 정형화되지 않거나 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.
우리는 지금 딱히 DB 저장소가 정해지지 않았다는 가정으로 진행하고 있다. 만일 나중에 Repository 클래스를 기존 코드를 일절 손대지 않고 바꿔치기 해야할 상황이 생긴하면 자바 코드를 통한 스프링 빈 등록 방법이 사용될 수 있을 것이다.
[References]
김영한님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
https://steady-coding.tistory.com/594
'개발 > Spring' 카테고리의 다른 글
[Spring Boot] 5. JPA 구현 (0) | 2022.08.24 |
---|---|
[Spring Boot] 4. 순수 JDBC 구현 (0) | 2022.08.23 |
[Spring Boot] 2. 회원 관리 예제 구현하기 (0) | 2022.08.12 |
[Spring Boot] 1. 정적 컨텐츠, MVC, API (0) | 2022.08.08 |
[Spring Boot] 0. intelliJ에서 Spring 개발 환경 설정하기 (0) | 2022.07.25 |
블로그의 정보
Hi Rev
Rev_