TIL - JAVA spring DAY 8

jihan kong·2022년 1월 12일
0

JAVA spring 입문

목록 보기
10/20
post-thumbnail

컴포넌트 스캔과 자동 의존관계 설정

지금까지 회원 도메인과 리포지토리, 서비스 그리고 각 코드에 관한 테스트까지 개발하면서 숨가쁘게 달려왔다. 오늘은 화면에 이것을 나타내는 작업을 하기 위한 사전 준비를 해볼 것이다. 그러기 위해서는 Member Controller, View template 이 필요하다.

한편, Member controllermember service를 통해서 회원가입, 데이터 조회 등을 할 수 있다. 이와 같은 관계를 서로 의존관계가 있다고 표현한다. 의존관계를 나타내기 위해 우선, controller package 안에 memberController class를 만들어보자.

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 {

    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

위와 같이, @(annotation)으로 @Controller, @Autowired 가 class 위에 붙어있는 것을 볼 수 있다. 작동원리를 살펴보면 스프링 부트가 실행될 때, container가 생기게 된다. 그 container에 @Controller annotation이 붙은 class 즉, memberController 객체를 생성해서 spring에 넣어주게 된다. 그리고 spring이 관리하게 되는 것이다. 다시말해, spring container에서 spring bean이 관리되는 것이다.

조금 더 직관적으로 살펴볼 수 있도록 DAY3 MVC 템플릿 엔진에 대해 설명할때의 이미지를 다시 가져와보았다.

(사진 출처, 인프런, 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술, 강사: 김영한)

스프링 부트에서 스프링 컨테이너를 만들고 그 컨테이너는 bean처럼 helloController를 가지고 있는 것을 볼 수 있다. 이를 통해 스프링과 관련된 Controller 같은 것들이 동작을 할 수 있게 되는 것이다.

자 그렇다면, 스프링이 이제 관리하게 된다면 모두 스프링 컨테이너에 등록하고 컨테이너에서 꺼내 쓰도록 바꾸는 것이 더 편할 수 있겠다. 왜냐하면 굳이 memberService의 내용이 크게 바뀌지 않는 한, new로 객체를 생성할 필요가 없는 것이며 다른 클래스에서도 이를 접근하기 용이하도록 하기위해서이다.

따라서 위의 코드처럼 new가 아닌 private final로 memberService를 선언하고, 대신에 memberService 에 관한 생성자를 만들게 되었다.
또한, @Autowired를 붙여준 이유는 spring container에서 MemberController가 동작할때, 생성자를 호출을 하게 된다. 그런데 생성자에 @Autowired라고 붙어있으면 spring이 container안의 memberService를 가져다가 연결을 시켜준다.

그런데 이를 동작시켜보면...

이와 같은 에러가 뜨게 된다. container안의 MemberServiceHelloController가 연결이 안되는 모양인데 왜 이런 현상이 일어나게 될까?

강사님께서 설명하시길 MemberService class는 순수한 자바 클래스이기 때문에 spring 입장에서는 이를 알 수 있는 방법이 없다고 하셨다. 따라서 다음과 같이 MemberService class에 annotation을 추가하면서 해결할 수 있었다.

@Service
public class MemberService {

    private final MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

@Service를 보고 비로소 spring이 container에 MemberService를 넣어줄 수 있게 된다.

@Repository
public class MemoryMemberRepository implements MemberRepository{

(MemoryMemberRepository class에도 마찬가지로 @Repository 를 붙여준다.)

이와 같이 스프링 빈을 통해,
Controller로 외부 요청을 받고, Service에서 비즈니스 로직을 만들고, Repository에서 데이터를 저장하는 정형화된 패턴을 만들어낼 수 있는 것이다.

(helloController 생성 -> spring bean에 등록된 memberService 객체를 집어넣어줌 (DI) -> memberService 생성 -> spring container에 memberService 등록 -> spring container 안에 있는 memberRepository 객체를 집어넣어줌)

스프링 빈 등록

한 편, 스프링 빈을 등록하는데에는 2가지 방법이 있다.

  1. 컴포넌트 스캔과 자동 의존관계 설정
  2. 자바 코드로 직접 스프링 빈 등록하기 (다음 시간에 살펴볼 예정)

우리가 지금까지 학습한 @Controller, @Service, @Repository와 같은 방식이 컴포넌트 스캔 방식이다. 왜 컴포넌트 스캔이라는 이름이 붙었는가하면 @Controller, @Service와 같은 코드에 들어가보면

이와 같이, Component 구조로 이루어져 있는 것을 볼 수 있다. 즉, 정리하자면...

  • @Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다.
  • @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.
  • @Component 를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
    • @Controller
    • @Service
    • @Repository

이처럼 annotation이 있으면 스프링 빈으로 자동 등록이 되며, 앞으로 스프링을 사용하면서 왠만한 것들은 다 스프링 빈으로 등록을 해서 쓰는 것이 이점이 많기 때문에 더욱 좋다고 하셨다.

오늘 학습한 내용은 그동안 잘 이해하지 못했던 DI에 관한 궁금증을 어느정도 해소시켜주게 되는 내용이었다. 그리고 스프링이 스프링 컨테이너와 빈을 통해 효율적으로 작동하고 있다는 것을 다시 한번 느꼈다. 스프링 빈과 그것에 wired 되어 작동되는 원리들... 복습하고 각인하자!

profile
학습하며 도전하는 것을 즐기는 개발자

0개의 댓글