TIL/JAVA

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

아람2 2025. 1. 1. 00:03
반응형

듣고 있는 강의 - 김영한의 Spring 입문편 

 

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

https://helloahram.tistory.com/195 에서 만들었던 서비스를 화면에 붙이기 위해서는 

Controller 와 ViewTemplate 이 필요하다 

 

MemberController 는 MemberService 를 통해서 회원가입을 하고 데이터를 조회할 수 있어야 한다 

그런 관계를 의존 관계가 있다고 한다 

MemberController 만들고 의존관계 추가  

package hello.hello_spring.controller;

import hello.hello_spring.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;
    }
}

 

Autowired 를 쓰면 Spring 이 Spring Container 에 있는 memberService 를 가지고 와서 연결을 해준다 

이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI, Dependency Injection 이라고 한다 

 

그리고 https://helloahram.tistory.com/195 에서 만든 코드들에도 Autowired 를 붙이고 의존성을 주입하고,

Service, Repository 들에도 @Service, @Repository Annotation 을 붙여서 Spring Bean 에 등록한다 

MemberService Spring bean 등록 - @Service

@Service
public class MemberService {
    private final MemberRepository memberRepository;

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

MemberRepository Spring Bean 등록 

@Repository
public class MemoryMemberRepository implements MemberRepository {

 

memberService 와 memberRepository 가 Spring Container 에 Spring Bean 으로 등록되었다 

 

참고) 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본적으로 싱글톤으로 등록한다 

유일하게 하나만 등록해서 공유하기 때문에, 같은 스프링 빈이면 모두 같은 인스턴스이다 

싱글톤이 아니게 설정할 수도 있지만, 일반적으로 대부분 싱글톤을 사용한다고 한다 

 

DI, Dependency Injection 종류

1) 필드 주입 

선언만 할 수 있고, 변경을 할 수 없다

권장하지 않는 방법 

    @Autowired private MemberService memberService;

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

2) Settet 주입 

MemberController 를 호출할 때 Setter 가 Public 으로 열려 있어야 한다 (변경할 일은 없지만, Public 하게 노출된다) 

변경 호출하지 않아야 될 메서드가 호출될 수 있기 때문에 이 방법도 권장하지 않는다 

public class MemberController {
    private MemberService memberService;

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

3) 생성자 주입 

의존 관계가 실행 중에 동적으로 변하는 경우는 거의 없기 때문에 생성자 주입을 권장한다 

    private final MemberService memberService;

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

 

선생님 참고) 실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다 

그리고 정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다 

🐣 현재 작성한 코드에서는 DB 대신 MemoryMemberRepository 를 만들어서 데이터를 관리했는데 

스프링 빈으로 등록하면, 추후 강의에서 DB 로 변경할 때 코드를 거의 손대지 않고 간단하게 변경할 수 있다

컴포넌트 스캔을 사용하면 여러 코드를 바꿔야 한다 🐣

@Autowired 주의할 점

@Autowired 를 통한 DI 는 helloController, memberService 등과 같이 스프링이 관리하는 객체에서만 동작한다 

스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다 

@Configuration
public class SpringConfig {
//    @Bean // Bean 을 내가 등록할 거다
//    public MemberService memberService() {
//        return new MemberService(memberRepository());
//    }
//
//    @Bean
//    public MemberRepository memberRepository() {
//        return new MemoryMemberRepository();
//    }

}

🐣 위와 같이 @Bean 이 없는 상황이라면 아래의 @Autowired 는 무쓸모라는 뜻이다

왜냐하면 @Autowired 는 스프링 컨테이너에서 관리하는 객체 (스프링 빈) 을 찾아 주입하고

스프링은 어플리케이션 실행 시점에 스프링 컨테이너에서 관리하는 빈들 간의 의존성을 연결한다

따라서 스프링이 관리하지 않는 객체에 대해 @Autowired 를 사용하면 주입이 이루어지지 않는다 🐣

@Controller
public class MemberController {
    private final MemberService memberService;

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

 

🐣 아래는 추가 공부 내용 

@Autowired 를 통해 스프링 컨테이너가 의존성을 주입하는 과정 

1. 스프링 컨테이너가 빈을 생성 - 컨테이너는 SpringConfig 에서 정의된 @Bean 메서드를 호출해 빈을 생성한다 

2. 빈을 주입 - MemberController 생성자에서 @Autowired 를 사용해 스프링 컨테이너에 등록된 MemberService 를 찾아 주입한다 

(앞서 말한 것처럼 빈을 주입하는 방식은 생성자 주입, 필드 주입, Setter 주입이 있고, 생성자 주입이 권장된다)

스프링 빈 등록 방식 

1. @Bean 을 사용

@Configuration 클래스 내에서 @Bean 을 사용해 등록한다 

등록된 메서드의 반환값이 스프링 빈이 된다 

2. @Component 계열 어노테이션 사용

클래스에 @Component, @Controller, @Service, @Repository 를 붙이면 자동으로 스캔하고 빈으로 등록된다 

이러한 방식을 컴포넌트 스캔이라고 하며, 스프링 부트는 기본적으로 어플리케이션의 최상위 패키지를 기준으로 스캔한다 

빈 스캔 대상이 되려면 @ComponentScan 을 설정하거나 스프링 부트의 기본 스캔 패키지 구조에 있어야 한다 

@Service
public class MemberService {
    private final MemberRepository memberRepository;

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