일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 프로그래머스
- nestJS
- thymeleaf
- C++
- AWS
- C언어
- 스프링
- 시스템호출
- 구조체배열
- 가상면접사례로배우는대규모시스템설계기초
- TypeORM
- 카카오
- 컴포넌트스캔
- git
- 파이썬
- 카카오 코테
- 알고리즘
- 해시
- spring boot
- Spring
- python
- Nodejs
- 코딩테스트
- @Component
- OpenCV
- 코테
- nestjs typeorm
- nestjs auth
- @Autowired
- 카카오 알고리즘
- Today
- Total
공부 기록장 💻
[Spring] 스프링 빈과 의존관계 - 컴포넌트 스캔 또는 직접 자바 코드로 등록하기 (Spring Bean and Depedency Injection, Component Scan) 본문
[Spring] 스프링 빈과 의존관계 - 컴포넌트 스캔 또는 직접 자바 코드로 등록하기 (Spring Bean and Depedency Injection, Component Scan)
dream_for 2023. 1. 16. 10:30인프런 "스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술" 정리
스프링 빈과 의존 관계
스프링에서 Controller가 Service에 접근하고, Service가 Repository 를 통해 데이터베이스 혹은 내부 메모리에 접근하기 위해서는 아래와 같이 스프링 컨테이너에 의해 관리되는 자바 객체인 스프링 빈에 Controller, Service, Repository를 등록해주어야 한다.
참고로, 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때 기본적으로 싱글톤으로 등록한다. (유일하게 하나만 등록해서 공유한다는 의미이다.) 따라서 같은 스프링 빈이면 모두 같은 인스턴스이다.
회원 컨트롤러가 회원 서비스, 그리고 회원 레포지터리를 사용할 수 있게 의존 관계를 준비해보자.
우선 회원 컨트롤러인 MemberController을 controller 패키지 내에 만들고, @Controller 어노테이션을 클래스 이름 위에 추가하자.
이후 MemberService 객체 변수를 private final 형으로 지정하고, 생성자를 만들도록 하자.
MemberController 클래스의 생성자가 위와 같이 만들어졌으며, 생성자의 파라미터로는 MemberService가 지정되었다.
이때, 생성자 위에 @AutoWired 어노테이션을 붙여주는데,
생성자에 @Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아 넣어준다. 이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI (Dependency Injection), 의존성 주입이라 한다.
위의 동작만으로는, memberService가 스프링 빈으로 등록되어 있지 않기 때문에 memberController가 memberService에 접근할 수 없게 된다.
따라서 controller가 service를, 그리고 service가 repository를 사용할 수 있도록 스프링 빈에 각 객체를 등록해주는 과정이 필요하다. 스프링빈을 등록하는 2가지 방법에는 1. 컴포넌트 스캔으로 자동 의존 관계 설정, 2. 자바 코드로 직접 스프링 빈 등록 하는 방법이 있다.
1. 스프링 빈 등록: Component Scan을 이용한 자동 의존관계 설정
먼저 어노테이션을 이용하여 스프링이 자동으로 연관된 객체를 스프링 컨테이너에 찾아 의존성을 주입해주는 컴포넌트 스캔 방법을 이용해보자.
컴포넌트 스캔은 @Component 를 명시하여 빈을 추가하는 방법이다. 클래스 위에 @Component 를 붙이면 스프링이 자동적으로 스프링 컨테이너에 빈을 등록한다.
컴포넌트 스캔의 대상
@Component 외에 @Controller, @Service, @Repository, @Configuration 은 @Component의 상속을 받고 있으므로 모두 컴포넌트 스캔의 대상이다.
- @Controller : 스프링 MVC 컨트롤러로 인식된다.
- @Repository : 스프링 데이터 접근 계층으로 인식하고 해당 계층에서 발생하는 예외는 모두 DataAccessException으로 변환한다.
- @Service : 특별한 처리른 하지 않으나, 개발자들이 핵심 비즈니스 계층을 인식하는데 도움을 준다.
- @Configuration : 스프링 설정 정보로 인식하고, 스프링 빈이 싱글톤을 유지하도록 추가 처리를 한다.
다시 말해. 컴포넌트 스캔은 @Component 어노테이션이 있는 경우 스프링 빈으로 자동 등록 해주는 기능을 말한다. @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔의 원리 때문이다.
@Component를 포함하는 @Controller, @Service, @Repository도 마찬가지로 스프링 빈으로 자동 등록된다.
Controller는 위에서 @Controller을 붙여 스프링 빈 등록을 마쳤으므로,
MemberService, MemoryMemberRepository 구현체에 각각 @Service, @Repository 어노테이션을 붙여주자.
2. 스프링 빈 등록 - 자바 코드로 직접 빈에 등록하기
이번에는 어노테이션을 이용해 자동으로 스프링 빈에 등록하는 방법이 아닌, 자바 코드를 작성하여 직접 스프링 빈에 등록하는 방법이다.
컨트롤러 부분의 @Controller 어노테이션을 제외한, @Service와 @Repository 어노테이션은 제거해주자.
이제 다음과 같이 main 메서드를 포함하는 HelloSpringApplication 이 존재하는 hellospring 디렉터리 바로 아래에 SpringConfig 클래스를 만들자.
이후 @Configuration 어노테이션을 추가해준 후에, @Bean 어노테이션을 이용해 회원 Service와 Repository를 빈에 등록해보자.
MemberService와 MemberRepository를 반환하는 memberService(), memberRepository() 메서드를 각각 작성해준다.
이 때 MemberService에는 MemberRepository를 파라미터로 주입해줘야 하므로,
반환하는 MemberService 객체의 파라미터로 memberRepisotiry() 메서드를 전달해주도록 위와 같이 코드를 작성해주면 된다.
참고할 사항들
1. 의존성 주입 DI 에는 총 3가지 방법(필드 주입, setter 주입, 생성자 주입)이 있는데, 의존 관계가 실행 중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.
2. 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 Component Scan 방법을 통해 스프링 빈에 등록한다. 정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 Configuration을 통해 스프링 빈으로 등록한다.
예를 들어, 위에서 Repository를 스프링 빈에 등록하기 위해 memberRepository() 메서드 내에서 MemoryMemberRepository() 클래스 객체를 반환하도록 하였다. 그런데 우리는 아직 DB에 직접적으로 연결하지 않고, Map<>() 클래스를 사용하여 내부 메모리를 사용하고 있는 상황이다. 따라서, 추후 내부 메모리가 아닌 데이터베이스에 연결하여 데이터들을 저장하고 관리하는 경우, 반환하는 클래스 구현체만 다른 클래스 구현체(예를 들면 DBMemberRepository와 같이 실제 데이터베이스와 연결하는 Repository로 변경해주면 기존 코드의 변형 없이 간단히 설정 변경이 가능하다.)
3. @Autowired를 통한 DI는 helloController, MemberService 등과 같이 스프링이 관리하는 객체(스프링 빈으로 등록이 완료된 객체)에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.
위에서 간단하게 살펴본 스프링 컨테이너, DI 와 관련된 내용은 추후 스프링 핵심 원리 강의를 수강하며 다시 정리할 예정이다.
[참고자료]
https://steady-coding.tistory.com/594