[스프링] 웹 MVC 및 DB 연동 - 4

스프링 빈과 의존관계

시작

스프링 빈 등록 및 의존관계 설정

MemberController 는 MemberService 를 통해 회원가입 및 Member 관련 기능을 사용해야한다. 이를 의존관계라고 한다.

@Controller 어노테이션을 사용하여 스프링 빈으로 등록한다. 이 빈은 스프링 컨테이너에 등록되고 관리된다.

스프링 빈으로 등록되면 new로 매번 생성하지 않고 스프링 컨테이너에서 관리되는 빈을 주입받아 사용할 수 있다.

우선 서비스 클래스에 @Service 어노테이션을 추가하여 스프링 빈으로 등록한다.

java
package hello.hello_spring.service;

// ...

@Service
public class MemberService {

    private final MemberRepository memberRepository;

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

Repository 또한 스프링 빈으로 등록해야한다. 이를 위해 @Repository 어노테이션을 추가한다.

java
package hello.hello_spring.repository;

// ...

@Repository
public class MemoryMemberRepository implements MemberRepository {
    // ...
}

이제 컨트롤러에서 서비스를 사용할 수 있도록 의존관계를 설정한다. 이를 의존성을 주입해주는 Dependency Injection 이라고 한다.

@Autowired 어노테이션을 사용하여 의존관계를 설정한다.

java
package hello.hello_spring.controller;

// ...

@Controller
public class MemberController {

    // private final MemberService memberService = new MemberService();

    private final MemberService memberService;

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

컨트롤러는 서비스를 의존, 서비스는 리퍼지토리를 의존합니다. @Autowired 어노테이션을 사용하여 의존관계를 설정합니다.

이렇게 하면 스프링 컨테이너는 필요한 객체를 자동으로 주입해줍니다.

스프링 빈을 등록하는 방법은 2가지가 있습니다.

  1. 컴포넌트 스캔과 자동 의존관계 설정
  • @Component 어노테이션이 있는 클래스를 스프링이 자동으로 찾아서 스프링 빈으로 등록
  • @Controller, @Service, @Repository 어노테이션은 모두 내부적으로 @Component를 포함
  • 스프링은 @SpringBootApplication이 있는 패키지와 그 하위 패키지를 자동으로 스캔
  • @Autowired를 통해 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 자동으로 주입
java
// @Controller

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}
  1. 자바 코드로 직접 스프링 빈 등록하기
  • @Configuration 클래스에 @Bean 어노테이션을 사용하여 수동으로 스프링 빈을 등록
  • 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈을 등록하는 방식을 선택
  • XML 설정 방식도 있지만 최근에는 잘 사용하지 않음

💡 스프링은 컨테이너에 스프링 빈을 등록할 때, 기본적으로 싱글톤으로 등록한다. 즉, 스프링 컨테이너는 하나만 생성하고 그 하나를 공유하여 사용한다.

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

@Configuration 어노테이션을 사용하여 스프링 빈을 등록합니다.

java
package hello.hello_spring;

import hello.hello_spring.repository.MemberRepository;
import hello.hello_spring.repository.MemoryMemberRepository;
import hello.hello_spring.service.MemberService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 스프링 빈 수동 등록을 위한 설정 클래스
 */
@Configuration
public class SpringConfig {

    /**
     * MemberService 스프링 빈 등록
     * memberRepository()를 주입받아 MemberService 인스턴스 생성
     * @return 생성된 MemberService 인스턴스
     */
    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }

    /**
     * MemberRepository 스프링 빈 등록
     * MemoryMemberRepository 구현체 사용
     * @return 생성된 MemberRepository 인스턴스
     */
    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}

이렇게 하면 스프링 컨테이너는 빈을 생성하고 관리하는 역할을 합니다.

어떻게 사용해야 하는가

  • 과거에는 XML로 설정했지만 최근에는 자바 코드로 직접 스프링 빈을 등록하는 방식이 더 많이 사용됩니다.
  • DI 에는 필드 주입, 생성자 주입, setter 주입 3가지가 있습니다. 의존 관계가 동적으로 변경되는 경우는 없으므로 생성자 주입을 권장합니다.
  • 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컨포넌트 스캔을 사용한다. 정형화되지 않거나 상황에 따라 구현 클래스를 변경해야 하면 @Configuration을 사용해 빈을 등록하는 방식을 사용한다.
  • 주의 : @Autowired를 통한 DI는 helloController, MemberService 등과 같이 스프링이 관리하는 객체 에서만 동작한다. 스프링 빈으로 등록하지 않고 직접 생성한 객체는 동작하지 않는다.