//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를 이용해 여러개의 빈을 받아온 후
사용시점에 동적으로 선택해 사용할 수 있다.
자동, 수동의 올바른 실무 운영 기준
- 편리한 자동 등록을 주로 사용하자
- 최근 스프링 부트는 컴포넌트 스캔을 기본으로 지원함
- 관리할 빈이 많아지면 수동 등록은 번거로움
- 자동 등록으로도 DIP,OCP 지킬 수 있음
- 수동은 언제 쓸까?
- 업무 로직 빈
- 웹을 지원하는 컨트롤러, 핵심 비즈니스 로직이 있는 서비스, 데이터를 처리하는 리포지토리등이 업무 로직
- 비즈니스 요구사항을 개발할 때 추가하거나 수정됨
- 숫자가 매우 많음, 보통 문제가 발생하면 찾기 쉬움 → 자동 등록
- 기술 지원 빈
- 기술적인 문제나 AOP(공통 관심사)를 처리할때 주로 사용됨
- 데이터 베이스 연결, 공통 로직 처리
- 수가 적음, 그러나 광범위한 영향, 어디서 문제인지 찾기 힘듦 → 수동 등록
- 수동 등록 후 설정 정보에 바로 나오도록 하는게 유지보수 쉬움
- 업무 로직 빈
'Spring > Spring 기본' 카테고리의 다른 글
사지방에서 Spring boot로 토이 프로젝트를 진행하며 #1 - 프로젝트 설계 (3) | 2023.08.05 |
---|---|
사지방에서 Spring boot 공부하기 #5 - 스프링 빈 등록과 조회 (0) | 2023.04.22 |
사지방에서 Spring boot 공부하기 #4 - 스프링 빈이란? (0) | 2023.04.18 |
사지방에서 Spring boot 공부하기 #3 - IOC와 DI (0) | 2023.04.16 |
사지방에서 Spring boot 공부하기 #2 - 스프링과 객체지향 (2) | 2023.04.16 |