본문 바로가기
Java/Spring입문

Spring 입문(9) 스프링 빈과 의존관계-자바 코드로 스프링 빈 등록

by 이쟝 2023. 5. 3.
인프런의 김영한님의 스프링입문 강의를 듣고 정리한 내용입니다.

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

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

 

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

회원 서비스와 회원 레포지토리의 @Service @Repository @Autowired 애너테이션을 제거한다. 

 

1. hello.hellospring 패키지에 SpringConfig.java 클래스를 생성한다.

src > main > java > hello > hellospring > SpringConfig.java 
package hello.hellospring;

import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.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();
    }
}
1. SpringConfig에 @Configuration
2. MemberService 메서드, MemberRepository에 @Bean 애너테이션으로 스프링 빈 등록하고 구현부 작성
-> 이 때 MemberService 생성자로 MemberRepository 파라미터가 필요하므로 밑에 선언한 MemberRepository 메서드가 반환하는 MemoryMemberRepository 인스턴스를 생성자에 주입시켜 준다.

MemberController

package hello.hellospring.controller;

import hello.hellospring.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;
    }
}
Controller는 어쩔 수 없이 스프링이 관리하는 것이기 때문에 @Controller는 컴포넌트 스캔으로 자동적으로 스프링 빈에 등록이 되고, 컴포넌트 스캔으로 인해서 @Autowired로 MemberService와 연결된다. 

 

*이렇게 되면 모두 연결된다*

 

*여기서는 향후 메모리 레퍼지터리를 다른 레퍼지터리로 변경할 예정이므로, 컴포넌트 스캔 방식 대신에 자바 코드로 스프링 빈을 설정할 것이다.*

- XML로 설정하는 방식도 있지만 최근에는 잘 사용하지 않으므로 생략한다. 

- DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다. 의존관계가 실행 중에 동적으로 변하는 경우는 거의 없기 때문에 생성자 주입을 권장한다. 
(실행중에 동적으로 변한다는 의미는 서버가 떠있는 중간에 바꿔치기가 된다는 의미인데, 이런 일은 거의 없고 그런 일이 일어난다면 Config 파일을 수정하고 서버를 다시 올리면 된다.)
// 생성자 주입: 사용 권장
@Autowired
public MemberController(MemberService memberServive){
	this.memberService = memberService;
}


// 필드 주입: 바꿀 수 있는 방법이 없어서 사용 권장 xx
@Autowired
private MemberService memberService;


// setter 주입: public으로 노출되는데 잘못 바뀌면 문제가 생겨서 사용 권장 xx
@Autowired
public void setMemberService(MemberService memberService){
	this.memberService = memberService;

}

 

- 실무에서는 주로 정형화된 컨트롤러, 서비스, 레퍼지터리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고 정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다. 

기존에 운영중인 코드를 하나도 안 고치고 바꿀 수 있는 방법 -> config파일을 따로 관리하는 것
@Configuration
public class SpringConfig {

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

    @Bean
    public MemberRepository memberRepository(){
        return new DbMemoryMemberRepository();
    }
}​

 

- 다른코드를 전혀 손댈 필요 없이 이렇게 config파일에서 Db로만 바꿔주면 된다! 컴포넌트 스캔을 사용하면 여러 코드를 바꿔야 하는 상황이 오는데, 직접 설정해주면 그럴 필요가 없다.

 

*주의: @Autowired를 통한 DI는 `helloController`, `MemberService등과 같이 스프링이 관리하는 객체에서만 동작한다. 컴포넌트 스캔이나 스프링 빈으로 등록하지 않고, 생성자에 @Autowired를 하면 적용되지 않는다. 우선 스프링 빈에 등록이 되어 있어야 @Autowired로 연결되기 때문이다.