Backend/Spring

[Spring] 스프링 빈과 의존관계

JOYERIM 2023. 2. 4. 13:13

 

 

 

 

거의 반년동안 스프링 스터디에서 진행하였던 블로그 프로젝트가 마무리가 되고

현재는 김영한님의 강의를 보면서 부족했던 부분을 보완하고 있다!

 

 

그 당시에 스프링을 처음 접하기도 하고 그때그때 필요한 부분들을 공부하는 방식으로 프로젝트를 하였더니 장단점이 분명했다.

단점은 순차적인 방식으로 공부를 하지 않아 부족한 개념들이 있다는 것이고, 장점은 그렇기 때문에 삽질 과정에서 얻은 것들도 많았다. (삽질은 옳다.)

 

 

부족했던 개념 중 하나가 스프링 빈과 의존관계였다. 스터디에서 다른 분들은 자바 코드로 직접 스프링 빈을 등록하는 방식으로, 나는 컴포넌트 스캔과 자동 의존관계 설정하는 방식으로 하였다. 그 당시에는 두 방식의 차이와 동작 방식에 대한 이해가 부족하였다.

 

 

그래서 이번 포스트에서는 부족했던 개념 중 스프링 빈과 의존관계에 대해 정리하려고 한다!

참고로, 대부분의 내용은 김영한님의 강의를 토대로 하였다.

 

 

 

 


 

 

 

 

해당 포스트에서는 아래 사진의 의존 관계를 가지도록 설정하고자 한다.

 

 

 

 

먼저, 회원 컨트롤러가 회원 서비스와 회원 리포지토리를 사용할 수 있도록 회원 컨트롤러에 의존관계를 추가하자.

 

 

@Controller
public class MemberController {

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

 

 

생성자에 @Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다. 이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI(Dependency Injection), 의존성 주입이라고 한다.

 

 

참고로 @Autowired를 통한 DI는 스프링이 관리하는 객체에서만 동작한다. 즉, 스프링 빈으로 등록하지 않은 객체에서는 동작하지 않는다.

 

 

@Controller 어노테이션을 이용해 스프링 빈으로 자동 등록된다.

 

 

아직 회원 서비스가 스프링 빈으로 등록되어 있지 않다.

 

 

 

그렇다면 회원 서비스를 스프링 빈으로 등록하도록 하자.

 

 

스프링 빈을 등록하는 방법은 크게 세가지가 있다.

 

- 컨포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
- xml

 

xml으로 설정하는 방식은 실무에서 거의 사용되지 않으므로 나머지 두 방법에 대해서 알아보자.

 

 

 

 

 

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

 

 

컴포넌트 스캔 원리

@Component 어노테이션이 있으면 스프링 빈으로 자동 등록된다.

@Controller 어노테이션 또한 스프링 빈으로 자동 등록되는데, 내부를 까보면 @Component를 포함하고 있기 때문이다.

 

 

 

마찬가지로, @Service, @Repository@Component를 포함하여 스프링 빈으로 자동 등록된다.

 

 

컨포넌트 스캔을 이용해 회원 서비스를 스프링 빈으로 등록하자.

 

@Service
public class MemberService {

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

 

 

생성자에 @Autowired를 사용하면 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입한다. 참고로, 생성자가 1개만 있으면 @Autowired를 생략할 수 있다.

 

 

마찬가지로 회원 리포지토리를 스프링 빈으로 등록하자.

@Repository
public class MemoryMemberRepository implements MemberRepository {}

 

 

이 과정을 통해 아래 의존관계를 가지게 된다. 위 과정을 간략하게 말하자면 @Component는 스프링 빈으로 등록하는 역할, @Autowired는 해당하는 스프링 빈을 찾아서 연결해주는 역할을 하는 것이다.

 

 

 

 

 

 

자바 코드로 직접 스프링 빈 등록하기

 

 

이 방법은 위 방식처럼 @Service, @Repository, @Autowired 어노테이션을 사용하지 않는다.

따로 Config 파일을 만들어 빈 등록을 해주는 방식이다.

 

 

@Configuration
public class SpringConfig {
    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }
    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}

 

 

주의

컨트롤러는 @Controller, @Autowired를 이용해 빈 등록과 의존관계 설정을 해주어야 한다.

 

 

 

 

비교

 

두 방법 모두 장단점이 있기 때문에 둘 다 알고 있어야 한다. 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 반대로 정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다. 예를 들어 다른 리포지토리로 변경할 예정이라면 자바 코드로 스프링 빈을 설정하면 굉장히 편하다. (config 파일만 변경해주면 됨.)

 

 

 

 

DI 방식

 

DI에는 3가지 방법(필드 주입, setter 주입, 생성자 주입)이 있다. 의존 관계가 실행 중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다. 참고로 테스트 코드에서는 필드 주입을 하는 경우가 많다. (귀찮으므로..)

 

 

 

 


 

 

 

 

사실 이번 포스트에서는 스프링 빈과 의존관계의 기초만 다룬 것이기 때문에 다음에 더 공부하여 정리할 예정이다.

비록 아직은 애송이지만 스프링 공부하면서 느끼는 건 공부할수록 재밌다.

 

 

어떻게 사용하면 되는지를 아는 것에 그치지 않고, 머릿속으로 논리 흐름을 다 파악할 수 있도록 더 노력하자.

조에림 파이팅 !~!!