옌의 로그

[Spring] 스프링 입문 | 4. 스프링 빈과 의존관계 본문

스터디/스프링

[Spring] 스프링 입문 | 4. 스프링 빈과 의존관계

dev-yen 2023. 7. 6. 22:49

https://inf.run/8u6a

 

[무료] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링 웹 애플리케이션 개발 전반을 빠르게 학습할 수 있습니다., 스프링 학습 첫 길잡이! 개발 공부의 길을 잃지 않도록 도와드립니다. 📣 확인해주세

www.inflearn.com

(본 게시글은 인프런 스프링 입문 강의에 의해 작성되었습니다.)

 

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

회원 컨트롤러가 회원 서비스와 회원 리포지토리를 사용할 수 있게 의존관계를 준비하자

 

회원 컨트롤러에 의존관계 추가

package yenie.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.beans.factory.annotation.Autowired;
import yenie.hellospring.service.MemberService;

@Controller
public class MemberController {

    private final MemberService memberService;
    
    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}
  • @Autowired : 스프링 컨테이너가 관리하는 빈(Bean)을 자동으로 찾아 해당 의존성을 주입한다
    • 이와 같이 객체 의존관계를 외부에서 넣어주는 것을 DI(Dependency Injection), 의존성 주입이라 한다
    • 이전 게시글에서 DI는 개발자가 직접 주입했고, 여기서는 @Autowired 에 의해 스프링이 주입해준다
  • 스프링 빈 (Spring Bean)
    • 스프링 프레임워크에서 관리되는 객체, 즉 스프링의 IoC(Inversion of Control) 컨테이너에 의해 생성, 관리, 조립되는 객체
    • 일반적으로 @Component, @Service, @Repository, @Controller 등과 같은 어노테이션을 사용해 클래스에 표시됨
    • 특징 (추후에 다시 자세히 다루겠습니다)
      • 생명주기관리
      • 의존성 주입
      • 스코프 관리
      • 관점 지향 프로그래밍(AOP) 지원
      • 수동 설정 가능

 

hellospring 애플리케이션을 실행하면 다음과 같은 오류가 발생하는데,

Consider defining a bean of type 'yenie.hellospring.service.MemberService' in your configuration.

이는 memberService가 스프링 빈으로 등록되어 있지 않기 때문에 발생한다.

  • helloController의 경우, 스프링이 제공하는 컨트롤러여서 스프링 빈이 자동으로 등록된다
  • @Controller 가 있으면 자동 등록된다

 

스프링 빈을 등록하는 2가지 방법 

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

컴포넌트 스캔 원리

  • 컴포넌트 스캔 : 자동으로 빈(Bean)을 검색하고 등록하는 방식
  • 주로 어노테이션을 기반으로 동작
  • 스프링은 클래스 경로를 스캔하여 특정 어노테이션이 적용된 클래스를 찾고, 해당 클래스를 스프링 빈으로 등록한다
    • @Component 어노테이션이 있으면 스프링 빈으로 자동 등록
    • @Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.
      • @Controller 어노테이션을 뜯어보면 안에 @Component 어노테이션을 포함하고 있다.
      • @Controller, @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 {}

 

스프링 빈 등록 이미지

 

스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다. 
  • 싱글톤(유일하게 하나)
  • 싱글톤 스코프의 스프링 빈은 애플리케이션 전체에서 오직 하나의 인스턴스만 생성되어 공유된다
  • 이는 동일한 스프링 빈을 (여러곳에서) 요청하면 항상 동일한 인스턴스를 반환한다는 의미이다
  • 모든 스프링 빈이 싱글톤인 것은 아니며, 스코프 설정에 따라 다른 인스턴스를 가질 수도 있다

 

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

(회원 서비스와 회원 리포지토리의 @Service, @Repository, @Autowired 어노테이션을 제거하고 진행한다)

src/main/java/hellospring/SpringConfig.java

package yenie.hellospring;

import yenie.hellospring.repository.MemberRepository;
import yenie.hellospring.repository.MemoryMemberRepository;
import yenie.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();
    }
    
}
  • 각각 클래스에 맞는 어노테이션(@Service, @Repository)을 붙여 스프링 빈에 등록하는 컴포넌트 스캔과 달리 자바 코드로SpringConfig 클래스 파일을 만들어 한 번에 스프링 빈을 등록할 수도 있다.
  • XML로 설정하는 방식도 있으나 최근에는 잘 사용하지 않는다
  • 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다
    • 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록
  • @Autowired를 통한 DI는 스프링이 관리하는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않음

 

DI 방법

  • 필드 주입
    • 의존성을 클래스의 필드에 직접 주입하는 방법
    • 클래스의 필드에 @Autowired 어노테이션을 사용하여 의존성을 주입하며, 스프링이 해당 필드를 자동으로 주입한다
public class MyClass {
    @Autowired
    private SomeDependency dependency;
}
  • setter 주입
    • 의존성을 세터 메서드를 통해 주입하는 방법
    • 클래스에 의존성을 설정하는 세터 메서드를 정의하고, 스프링이 해당 의존성을 자동으로 주입
public class MyClass {
    private final SomeDependency dependency;

    public MyClass(SomeDependency dependency) {
        this.dependency = dependency;
    }
}
  •  생성자 주입
    • 의존성을 객체 생성 시에 생성자를 통해 주입하는 방법
    • 클래스의 생성자에 의존성을 받을 매개변수를 선언하고 스프링이 해당 의존성을 자동으로 주입 (현재 헬로스프링 예제에서 사용한 방법)

 

번외

 

Comments