| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- DLQ
- @Transactional
- 지연 로딩
- Spring
- JPA
- redis
- 페이징
- 컨테이너
- @ComponentScan
- Web
- docker
- docker compose
- CORS
- Spring Data JPA
- JPQL
- Spring Container
- 쿠버네티스
- Routing Key
- 서블릿 컨테이너
- DI
- securitycontextholderfilter
- AWS
- 스프링 부트
- Dead Letter Queue
- dockerhub
- JWT
- mybatis
- kafka
- JdbcTemplate
- MSA
- Today
- Total
look-forest
스프링 빈과 의존 관계 본문
의존 관계?
2021.04.07 - [Spring/spring 핵심 원리] - Spring이란?
controller가 service를 통해서 기능(데이터 조회 등)
=> '의존관계가 있다', 'XXController가 XXService를 의존한다'라고 표현한다.
이 작업을 spring스럽게 해보자!
문제가 되는 상황
매번 의존 관계를 생성자를 통해 직접 주입해준다면,
불필요하게 여러 인스턴스를 만들어야 하고, 구현체 변경시 코드를 변경해야 한다.

예를 들어 AdminController 에서도 memberRepository, memberService 객체를 만들어야 한다.
이때 동일한 memberRepository가 아닌 것도 문제가 되고,
구현체를 DBRepository로 변경할 경우 직접 관련 파일들을 뒤져 코드를 바꿔야 한다..
Spring스러운 의존 관계 설정 방법
- 컴포넌트 스캔과 자동 의존 관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
1. 컴포넌트 스캔과 자동 의존 관계 설정
# 컴포넌트 스캔
spring이 애플리케이션의 하위 패키지를 뒤져서 @Component를 container에 bean으로 등록하는 것.
spring이 뜰 때 spring container가 생긴다.
컨테이너에는 객체를 담아 관리한다. (componentScan 등으로)
담긴 객체를 spring bean이라 한다.
기본적으로 container는 bean을 singleton으로 관리한다
유일하게 하나만 등록해서 공유한다.
프로토타입으로 설정할 수도 있지만, 대부분 싱글톤을 사용한다.
컴포넌트 스캔의 대상: @Component
@Controller, @Service, @Repository, @Configuration 등은 @component를 포함한다.
@Controller를 까보면
![]()

컴포넌트 스캔의 범위
@ComponentScan이 속한 패키지의 하위 클래스들을 뒤져 @Component가 붙어 있으면 빈으로 등록한다.

실제로 @SpringBootApplication을 까보면 @ComponentScan이 있다

spring이 뜰 때 해당 패키지를 컴포넌트 스캔해서 객체를 생성하고 빈으로 등록한다. (빈 끼리는 Autowired도 해준다)
# 자동 의존 관계 설정(Autowired)
@Autowired가 붙어 있으면 객체 생성 시점에 스프링이 컨테이너에서 필요한 빈을 찾아 주입해준다.
이렇게 의존 관계를 외부에서 넣어주는 것을 DI(Denpendency Injection)이라 한다.
[Spring/spring 핵심 원리] - IoC? DI? 컨테이너?

하지만 실행해보면 에러가 난다.

MemberService가 Spring bean으로 등록되어 있지 않기 때문이다.
따라서 컴포넌트 스캔의 대상이라는 애노테이션을 붙여준다.

※ 생성자가 1개만 있으면 @Autowired는 생략할 수 있다.
Autowired의 범위
1. 스프링이 관리하는 객체(빈)만을 대상으로 동작한다.

2. 스프링 빈으로 등록하지 않고 직접 생성한(new) 객체에서는 동작하지 않는다.
스프링을 띄울 때 MemberService 객체 하나를 빈으로 등록했지만,
로직 중에 직접 생성할 경우에 @Autowired 안 먹힌다.



DI의 3가지 방법
1) setter 주입
그러나 setter는 public으로 열려있어서 문제가 생길 수 있다.

2) 생성자 주입
애플리케이션 로딩 시점에 조립될 때만 변경되어 좋다
3) field 주입

단위 테스트 실행 시, 스프링 컨테이너의 도움없이 여러 객체를 자유롭게 변경하면서 테스트할 수 있어야 한다
그런데 필드 주입을 사용하면 스프링 컨테이너가 없을 땐 의존하는 객체를 변경할 수 있는 방법이 없다
반면 생성자 주입은 컨테이너의 도움없이 직접 new XXXService()와 같은 방식으로 객체를 마음대로 변경하면서 테스트하거나 실행할 수 있다.
문제 해결?
이제 memberController, memberService, memberRepository가 컨테이너에 빈으로 등록되었기 때문에
adminService가 memberRepository를 필요로 하더라도 하나의 인스턴스를 공유해서 쓸 수 있다.

그런데 구현체를 바꿀 경우 코드 변경은 어떻게 될까?
2. 자바 코드로 직접 스프링 빈 등록하기
직접 설정 파일을 만들어 등록할 빈을 정의한다.

참고로 @Controller는 있어야 한다.
스프링은 @Controller가 있어야 MVC 컨트롤러로 인식. 스프링 빈으로 컨트롤러를 등록해야 한다.
Autowired가 더 편한데 직접 빈 등록하는 방법을 왜 알아야 할까?
@Configuration 방식은 기존 코드에 손대지 않고 상황에 따라 구현 객체를 바꿔야할 때 유용하다.
컴포넌트 스캔을 사용하면 여러 코드를 바꿔야 하지만, @Configuration 방식은 설정 파일에서 구현체만 바꿔주면 된다.
한 곳에(설정 클래스) 모여 있기 때문에 유지보수하기 유리하다!
예를 들어


즉, 정형화되지 않거나 상황에 따라 구현 클래스를 변경해야 하면 설정 클래스를 통해 스프링 빈으로 등록!
그 외 정형화된 Controller, Service, Repository 같은 코드는 컴포넌트 스캔 사용!
이런 이유 때문에 spring을 쓰는 것이다!
객체지향 설계가 좋다좋다 하는 이유는 다형성을 활용해서, 인터페이스를 두고 구현체를 바꿔 끼울 수 있기 때문!
spring은 이마저도 편리하게 스프링 컨테이너를 통해 지원해준다.
컨테이너에 등록되어 있는 빈을 자동으로 주입(DI)해주므로, 어떤 빈을 넣을지만 Config에서 바꿔주면 된다!!
참고 자료
스프링 입문(김영한 님)
'Spring > Spring 웹 개발 큰 그림' 카테고리의 다른 글
| AOP (0) | 2021.05.02 |
|---|---|
| 스프링 DB 접근 기술(신) (0) | 2021.05.01 |
| 스프링 DB 접근 기술(구) (0) | 2021.05.01 |
| Spring 웹 개발 기초 (0) | 2021.04.24 |
| 프로젝트 환경 설정 (0) | 2021.04.24 |