//MemberServiceImpl
@Component
public  class MemberServiceImpl implements MemberService{
    private final MemberRepository memberRepository;
    
    public MemberServiceImpl(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }
    
    public void join(Member member){
        memberRepository.save(member);
    }
    
    public Member findMember(Long id){
        return memberRepository.findById(id);
    }
}

//MemoryMemberRepository
@Component
public class MemoryMemberRepository implements MemberRepository{
    private static Map<Long, Member> store = new HashMap<> ();
    
    @Override
    public void save(Member member){
        store.put(member.getId(), member);
    }
    @Override
    public Member findById(Long id){
        return store.get(id);
    }
}

다음과 같이 컴포넌트 어노테이션을 이용해 스프링 빈에 자동으로 인스턴스를 등록할 수 있다.

문제는 MemberServiceImpl 객체는 MemberRepository 인터페이스와 의존관계를 가지고 있다.

 

수동 빈 등록에선 AppConfig 파일에서 직접 의존관계를 주입해줬는데 자동 등록에선 어떻게 의존관계를 설정할까??

 

@Autowired - 자동 의존관계 주입

//MemberServiceImpl
@Component
public  class MemberServiceImpl implements MemberService{
    private final MemberRepository memberRepository;
    
    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }
    
    public void join(Member member){
        memberRepository.save(member);
    }
    
    public Member findMember(Long id){
        return memberRepository.findById(id);
    }
}

@Autowired는 자동 의존관계 등록 어노테이션이다.

Autowired를 달아놓으면 스프링이 컴포넌트 스캔 후 빈을 등록할 때 자동으로 의존관계를 주입시켜준다.

 

스프링 빈이 컴포넌트 스캔을 할때 생성자에 Autowired 어노테이션이 붙은 인스턴스는

생성자의 파라미터를 보고 같은 타입의 빈을 자동으로 주입해준다.

 

중복 등록과 충돌

@Component
public class MemberA{}

@Component
public class MemberB {}


@Component
public class MemberService{
    private Member member;
    
    @Autowired
    public MemberService(Member member){
    	this.member = member;
    }
}

만약 다음과 같이 같은 클래스 타입의 빈이 두 개 이상이라면 어떻게 될까??

 

NoUniqueBeanDefinitionException발생한다.

 

다음과 같은 오류를 해결하는 방법은

 

1. 이름으로 매칭

public class MemberService{
    private Member memberA;
    
    @Autowired
    public MemberService(Member memberA){

다음과 같이 필드명을 memberA라고 명시해주거나

@Autowired("memberA")
public MemberService(Member member){

어노테이션안에 이름을 입력해준다면 스프링이 이름이 동일한 memberA를 자동으로 주입해준다.

 

2. Qualifier 사용하기

@Component
@Qualifier("A")
public class MemberA{}

@Component
public class MemberB {}


@Component
public class MemberService{
    private Member member;
    
    @Autowired
    public MemberService(Member @Qualifier("A")member){
    	this.member = member;
    }
}

빈 이름이 아닌 추가 구분자를 제공하는 기능이다.

 

3. Primary 사용하기

@Component
@Primary
public class MemberA{}

@Component
public class MemberB {}


@Component
public class MemberService{
    private Member member;
    
    @Autowired
    public MemberService(Member member){
    	this.member = member;
    }
}

빈 등록시 우선순위를 지정해주는 방법이다.

여러개의 빈이 존재할 때 @Primary가 붙어있는 빈을 먼저 주입해준다.

 

 여러개의 빈을 조회해야 할때 - List, Map

예를 들면 방금과 같은 코드에서 서비스가 실행되기 전까지는

MemberA,MemberB 둘 중 어떤 인스턴스 빈을 사용할 지 모르는 상황이 생길 수 있다.

 

@Component
public class MemberA{}

@Component
public class MemberB {}


@Component
public class MemberService{
    private Map<String,Member> memberMap;
    private List<Member> memberList
    
    @Autowired
    public MemberService(Map<String,Member> memberMap, List<Member> memberList ){
    	this.memberMap = memberMap;
        this.memberList = memberList;
    }
}

그럴땐 Map,List를 이용해 여러개의 빈을 받아온 후

사용시점에 동적으로 선택해 사용할 수 있다.

 

자동, 수동의 올바른 실무 운영 기준

  1. 편리한 자동 등록을 주로 사용하자
    1. 최근 스프링 부트는 컴포넌트 스캔을 기본으로 지원함
    2. 관리할 빈이 많아지면 수동 등록은 번거로움
    3. 자동 등록으로도 DIP,OCP 지킬 수 있음
  2. 수동은 언제 쓸까?
    1. 업무 로직 빈
      1. 웹을 지원하는 컨트롤러, 핵심 비즈니스 로직이 있는 서비스, 데이터를 처리하는 리포지토리등이 업무 로직
      2. 비즈니스 요구사항을 개발할 때 추가하거나 수정됨
      3. 숫자가 매우 많음, 보통 문제가 발생하면 찾기 쉬움 → 자동 등록
    2. 기술 지원 빈
      1. 기술적인 문제나 AOP(공통 관심사)를 처리할때 주로 사용됨
      2. 데이터 베이스 연결, 공통 로직 처리
      3. 수가 적음, 그러나 광범위한 영향, 어디서 문제인지 찾기 힘듦 → 수동 등록
      4. 수동 등록 후 설정 정보에 바로 나오도록 하는게 유지보수 쉬움

 

 

 

+ Recent posts