본문 바로가기

스프링

스프링과 빈의 의존관계

728x90

컨트롤러를 통해서 외부의 요청을 받고, 서비스에서 비즈니스 로직을 만들고, 리포지토리에서 데이터를 저장하는 것이 정형화된 패턴

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


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

@Controller
public class MemberController {

    private final MemberService memberService;

    //스프링빈에 등록되어 있는 멤버서비스 객체를 가져와서 생성자에 넣어주며
    //이를 DI라고 한다.(의존관계를 기입)

    //멤버 컨트롤러를 스프링 컨테이너가 뜰 때 생성을 해줌
    //그 때 생성자를 호출하며, 그 때 @Autowired가 달려 있으면
    //멤버 서비스를 스프링이 스프링 컨테이너에 있는 멤버 서비스를 가져와서 연결을 시켜줌
    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

 

생성자에 @Autowired 가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어주며, 이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI (Dependency Injection), 의존성 주입이라 한다.

 

그런데 위와 같이만 하면 멤버 서비스 객체에서 에러가 나게 되는데 그 이유는 memberService가 스프링 빈으로 등록되어 있지 않아서 그렇다.

 

스프링 빈을 등록하는 방법에는 지금 알아볼 컴포넌트 스캔과 자동 의존관계 설정이 있고, 두 번째로 자바 코드를 통해 직접 스프링 빈을 등록하는 방법이 있다.

 

-----------

컴포넌트 스캔이라고 하는 이유는 스프링이 올라올 때 컴포넌트와 관련된 애너테이션이 있으면 스프링이 다 객체로 하나씩 생성을 해서 컨테이너에 등록을 하고, AutoWired는 이들의 연관관계를 이어주는 것으로 즉 저 위에서 화살표 처럼 선으로 연결해준다고 생각하면 된다.

 

이렇게 연결이 되었기 때문에 컨트롤러가 서비스를 쓸 수 있고, 서비스가 리포지토리를 쓸 수 있게 되는 것

-----------

컴포넌트 스캔 원리

@Component 애노테이션이 있으면 스프링 빈으로 자동 등록된다.


@Controller 컨트롤러가 스프링 빈으로 자동 등록된 이유도 컴포넌트 스캔 때문이다.


@Component 를 포함하는 다음 애노테이션도 스프링 빈으로 자동 등록된다.
 - @Controller
 - @Service
 - @Repository

 

회원 서비스 스프링 빈 등록

@Service //스프링이 올라올 때 서비스로 컨테이너에 멤버 서비스를 올려줌
public class MemberService {


    //테스트 클래스와 같은 인스턴스를 사용하게 바꾸려면 아래와 같이 바꾸면 됨
    private  final MemberRepository memberRepository;
    //직접 new로 생성하는 것이 아니라 생성자를 사용해서 외부에서 넣어주게 바꿔주면 됨
    @Autowired 
    //생성자를 호출할 때 필요한 매개변수가 무엇인지를 확인하고 
    //스프링 컨테이너에 있는 memberRepository를 넣어줌
    //현재 구현체로 있는 것은 MemoryMemberRepository이기 때문에 이를 서비스에 주입해줌
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

생성자에 @Autowired를 사용하면 객체 생성 시점에 스프링 컨테이너에서 해당 스프링 빈을 찾아서 주입한다. 생성자가 1개만 있으면 @Autowired 는 생략할 수 있다.

 

회원 리포지토리 스프링 빈 등록

@Repository //리포지토리로 설정
public class MemoryMemberRepository implements MemberRepository{

 

 

memberService 와 memberRepository 가 스프링 컨테이너에 스프링 빈으로 등록되었다.


스프링은 스프링 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다.(유일하게 하나만 등록해서 공유)

 

따라서 같은 스프링 빈이면 모두 같은 인스턴스다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다

 

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


@Configuration
public class SpringConfig {

    //스프링 빈을 등록한다는 의미
    //아래의 로직을 스프링 빈에 등록 - 멤버 서비스가 스프링 빈에 등록
    @Bean
    public MemberService memberService(){
        //멤버서비스는 생성자라서 멤버리퍼지토리 인스턴스가 들어와야 하며,
        //MemoryMemberRepository()를 받은 memberRepository()를 넣어줌
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository(){
        //MemberRepository의 구현체인 MemoryMemberRepository를 리턴
        return new MemoryMemberRepository();
    }
}

 

위의 클래스를 생성한 이후 회원 서비스와 회원 리포지토리의 @Service, @Repository, @Autowired 애노테이션을 제거해줌

 

//@Service //스프링이 올라올 때 서비스로 컨테이너에 멤버 서비스를 올려줌 - 자바 코드로 등록할 땐 사용x
public class MemberService {

    private  final MemberRepository memberRepository;
//    @Autowired - 자바 코드로 등록할 땐 사용x
    public MemberService(MemberRepository memberRepository) {
        //스프링 빈에 등록되어 있는 memberRepository를 MemberService에 넣어주게 되는 것
        this.memberRepository = memberRepository;
    }

 

//구현체
//@Repository //리포지토리로 설정
public class MemoryMemberRepository implements MemberRepository{

 

DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다. 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.

 

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


 그리고 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다. 상황에 따라 구현 클래스를 변경해야 한다는 말은 현재 진행중인 예제와도 관련이 있다. 

 처음에 주어졌던 비즈니스 환경이 DB가 아직 정해지지 않은 상황이었기 때문에 지금까지 임시로 MemoryMemberRespository 구현체를 만들어서 저장소 역할을 대신해왔다. 나중에 이 구현체를 다른 리포지토리로 변경할 때 진행중인 로직을 하나도 손대지 않고 그대로 바꿔치기 할 수 있는 방식이 있으며, 이를 위해서 현재 이러한 과정을 거치고 있다.

 그리고 이때 진행되는 것이 바로 상황에 따라 구현 클래스를 변경한다는 것이다. 컴포넌트 스캔을 사용하면 여러군데를 손대야 하지만 자바 코드로 스프링 빈을 등록하면 설정파일만 수정하면 그대로 사용이 가능해진다.

 

 @Autowired 를 통한 DI는 helloConroller , memberService 등과 같이 스프링이 관리하는 객체에서만 동작하며, 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.

 

 

728x90

'스프링' 카테고리의 다른 글

스프링 DB 접근 기술  (0) 2022.05.20
회원 관리 예제 - 웹 MVC 개발  (0) 2022.05.19
회원 관리 예제  (0) 2022.05.18
스프링 웹 개발 기초  (0) 2022.05.18
프로젝트 환경 설정  (0) 2022.05.17