Study/Spring Boot

[Spring Boot] 의존성 주입과 스프링 빈 등록

DevJaewoo 2022. 2. 13. 13:31
반응형

Spring LOGO

의존성 주입과 스프링 빈 등록

DB에 사용자 정보를 넣고 빼기 위해 Service와 Repository를 만들었다.

이제 웹을 통해 접근할 수 있도록 Controller를 만들어줘야 한다.

 

MemberController.java

package com.devjaewoo.hellospring.controller;

import com.devjaewoo.hellospring.repository.MemoryMemberRepository;
import com.devjaewoo.hellospring.service.MemberService;
import org.springframework.stereotype.Controller;

@Controller
public class MemberController {
    
}

 

이제 Service 변수를 생성해야 한다. Java에서 했던 것처럼 아래와 같이 만들면 될까?

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

 

아니다. MemberServiceMemberController 외에 다른 곳에서도 얼마든지 쓰일 수 있기 때문에

new로 선언하면 안 된다.

 

대신 생성자에 @Autowired라는 어노테이션을 통해 스프링 컨테이너에 있는

MemberServiceBean을 찾아서 의존 관계 주입 (DI)을 해야 한다.

 

package com.devjaewoo.hellospring.controller;

import com.devjaewoo.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;
    }
}

 

하지만 코드를 작성하면 아래와 같이 "Could not autowire, No beans of 'MemberService' type found."라는 에러 메시지가 뜬다.

 

@Autowired가 붙으면 해당 객체들을 스프링 컨테이너에서 빈으로 등록되어있는지 찾는데,

memberService가 스프링 빈에 등록되어있지 않기 때문이다.

bean 조회 오류

 

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

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

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

클래스 어노테이션에 @Component를 추가하면 자동으로 스프링 빈에 등록한다.

@Controller, @Service, @Repository 모두 @Component를 포함하는 어노테이션이기 때문에

각 클래스의 역할에 맞게 어노테이션을 달아주면 된다.

@Controller에 @Component 어노테이션이 붙어있는 모습

 

현재 MemberService 클래스가 Bean으로 등록되어 있지 않으니 @Service 어노테이션을 추가해주자.

MemberRepository@Autowired 해준다.

 

MemberService.java

@Service
public class MemberService {

    private final MemberRepository memberRepository;

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

 

MemberRepository 변수에 발생한 에러 역시 @Repository 어노테이션을 붙여 해결해주면 자동 의존관계 설정이 끝난다.

 

MemoryMemberRepository.java

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

 

현재 설정되어있는 구조를 아래의 그림처럼 표현할 수 있다.

bean 구조


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

실습을 위해 위의 수정사항에서 @Autowired는 남기고 @Service@Repository를 지워주자.

그다음 SpringConfig 클래스를 하나 만들고, @Configuration 어노테이션을 추가한다.

 

SpringConfig.java

package com.devjaewoo.hellospring;

import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringConfig {

}

 

이제 SpringConfig 클래스에 Bean을 정의할 수 있다.

@Service@Repository를 제거했으니 이곳에 새로 만들어주자.

 

Bean 정의는 @Bean 어노테이션으로 할 수 있다.

 

SpringConfig.java

package com.devjaewoo.hellospring;

import com.devjaewoo.hellospring.repository.MemberRepository;
import com.devjaewoo.hellospring.repository.MemoryMemberRepository;
import com.devjaewoo.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();
    }
}

 

이렇게 Component에 직접 어노테이션을 달아주지 않고 Config 파일에 Bean을 선언하면

처음엔 불편하지만 나중에 Bean 클래스를 교체할 때 생성할 다른 코드를 전혀 손댈 필요 없이

설정 파일만 바꿔주면 된다.

 

package com.devjaewoo.hellospring;

import com.devjaewoo.hellospring.repository.MemberRepository;
import com.devjaewoo.hellospring.repository.MemoryMemberRepository;
import com.devjaewoo.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();
        return new anotherMemberRepository();
    }
}

출처

반응형