스프링 빈을 등록하는 방법(컴포넌트 스캔/자바 코드로 등록)

2023. 12. 27. 19:06
728x90

생성자 주입

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

1) MemberController

2) MemberService

3) MemberRepository (interface) -> 구현체 MemoryMemberRepository

 

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

@Service
public class MemberService {
    private final MemberRepository memberRepository;

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

@Repository
public class MemoryMemberRepository implements MemberRepository {
    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L;
}
  • 생성자에 @Autowired를 달아 의존성을 주입해준다.  (단, 생성자가 1개만 있으면 @Autowired 생략 가능)
  • @Component 애너테이션이 있으면 스프링 빈으로 자동 등록됨.
  • @Controller, @Service, @Repository는 @Componenet를 포함하고 있어 스프링 빈으로 자동 등록된다. 

 

  • 스프링은 스프링 컨테이너에 스프링 빈을 등록할 때 기본적으로 싱클톤 패턴을 사용한다. (유일하게 하나만 등록할 수 있음. 같은 스프링 빈이면 모두 같은 인스턴스다. )
  • @SpringBootApplication 애너테이션에는 @ComponentScan을 포함하고 있어 자동으로 스프링 빈으로 등록된 @Component를 스캔한다. 

  •  결국 @SpringBootApplication이 달려있는 대표 Application 클래스가 포함되어있는 패키지 하위에서만 실행이 된다. 
  •  @Autowired를 통한 의존성 주입은 스프링이 관리하는 객체에서만 동작한다. (스프링 빈으로 등록하지 않고, 내가 직접 생성한 객체에서는 동작하지 않음.)

 

 

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

서비스와 레포지토리 클래스의 @Service, @Repository, @Autowired 없이 시작한다. 

1) SpringConfig 클래스(@Configuration으로 표시) 생성하여 그 안에 @Bean으로 등록한다. 

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

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository(); //구현체
    }

}

이렇게 하면 스프링이 뜨면서 Configuration태그를 읽고 그 안의 Bean태그들을 스프링 빈에 등록해준다.  그 안의 로직 그대로.

 

 

** 참고

: 실무에서는 주로 정형화된 컨트롤러, 서비스, 레포지토리 같은 코드는 > 컴포넌트 스캔을 사용.

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

(ex. 현재 MemoryMemberRepository인데,, 이것을 DbMemberRepository로 바꿔주는 과정.)

 

Dependency Injection 방법

1. 생성자 주입 >> 권장

@Controller
public class MemberController {
    private MemberService memberService;

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

2. 필드 주입

: 외부에서 접근이 불가능하다는 단점이 존재. 테스트 코드를 쓰기 위해서는 객체를 수정할 수 없는 필드주입은 비추..

@Controller
public class MemberController {
	@Autowired
    private MemberService memberService;

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

3. setter 주입

: set~이 public이어야 하기 때문에 주입받는 객체가 변경되는 문제가 생길 가능성이 있다. 

+ 주입할 대상이 없는 경우에 오류가 발생하는데 @Autowired(required=false)를 통해 설정 가능. 

@Controller
public class MemberController {
    private MemberService memberService;

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

 

 

** 왜 생성자 주입을 사용해야 할까?

1) 객체의 불변성 확보 : 의존 관계에서 변경이 필요한 상황이 거의 없다. 

2) 테스트 코드의 작성 : 테스트 코드는 가능한 순수 자바로 작성하는 것이 좋다. 또한 컴파일 시점에 객체를 주입받아 테스트 코드 작성이 가능해, 주입하는 객체가 누락된 경우 오류를 발견할 수 있다. 

3) final 키워드 : 생성자 주입시 필드 객체에 final 키워드 사용가능하므로 컴파일 시점에 누락된 의존성을 확인할 수 있다. (다른 주입 방법들은 객체 생성 이후에 호출되므로 final 사용 불가)

 

 

728x90

'Programming > 김영한 스프링 강의' 카테고리의 다른 글

why Spring Boot?  (0) 2024.04.11
의존성이 주입되는 과정...  (1) 2023.12.27
스프링 웹 개발 기초  (1) 2023.12.19
스프링 그리고 빌드  (0) 2023.12.18

BELATED ARTICLES

more