728x90
7.의존관계 자동주입
- 목차
- 1.다양한 읜존관계 주입 방법
- 2.옵션 처리
- 3.생성자 주입을 선택하라
- 4.롬복과 최신트렌드
- 5.@Autowired 필드명 , @Qualifier , @Primary
- 6.자동,수동의 올바른 실무운영기준
1.다양한 읜존관계 주입 방법
- 생성자 주입
- 수정자 주입 (setter)
- 필드 주입
- 일반 메서드 주입
OrderServiceImpl
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
//private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
- 생성자 호출 시점에서 딱1번 호출되는것을 보장
- 불변,필수 의존관계에 사용
- 생성자가 1개일 경우 @Autowired 를 생략해도 자동으로 주입된다
2.수정자 주입 (setter)
@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}
- 선택,변경 가능성있는 의존관계 사용
3.필드 주입
@Component
public class OrderServiceImpl implements OrderService {
@Autowired
private MemberRepository memberRepository;
@Autowired
private DiscountPolicy discountPolicy;
}
- 외부에서 변경이 불가능해서 테스트하기 힘들다
- DI 프레임워크가 없으면 안된다
- 테스트 코드 에서 사용하자
4.일반 메서드 주입
@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
- 한번에 여러필드를 주입 받을수 있다
- 일반적으로 잘 사용 안한다
2.옵션 처리
- 스프링 빈이 없이도 동작해야 할때가 있다
AutowiredTest
public class AutowiredTest {
@Test
void AutowiredOption(){
ApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
}
static class TestBean{
@Autowired(required = false)
public void setNoBean1(Member noBean1){
System.out.println("noBean1 = " + noBean1);
}
@Autowired
public void setNoBean2(@Nullable Member noBean2){
System.out.println("noBean2 = " + noBean2);
}
@Autowired
public void setNoBean3(Optional<Member> noBean3){
System.out.println("noBean3 = " + noBean3);
}
}
}
- @Autowired(required=false) : 자동주입할 대상이 없으면 수정자 메서드 자체가 호출안됨
- org.springframework.lang.@Nullable : 자동 주입할 대상이 없으면 null 입력
- Optional<> : 자동 주입할 대상이 없으면 Optional.empty 가 입력
3.생성자 주입을 선택하라
- 불변
- 대부분 의존관계 주입은 한번 일어나면 애플리케이션 종료시점까지 의존관계를 변경할일이 없다
- 수정자 주입을 사용할 경우 set 메서드를 열기때문에 누군가 실수로 변경할수 있다
- 불변으로 설계하는것이 중요하다
- 누락
- 프레임워크 없이 순수한 자바코드를 단위테스트 하는경우
OrderServiceImpl
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}
- 생성자 주입을 넣으면서 누락된 부분을 확인할수 있다
OrderServiceImplTest
class OrderServiceImplTest {
@Test
void createOrder(){
MemoryMemberRepository memoryMemberRepository = new MemoryMemberRepository();
memoryMemberRepository.save(new Member(1L,"name", Grade.VIP));
OrderServiceImpl orderService = new OrderServiceImpl(new MemoryMemberRepository(),new FixDiscountPolicy());
Order itemA = orderService.createOrder(1L, "itemA", 10000);
assertThat(itemA.getDiscountPrice()).isEqualTo(1000);
}
}
생성자 주입방식 정리
- 프레임워크에 의존하지않고 순수한 자바언어의 특징을 살리는 방법
- 기본으로 생성자 주입을 사용하고 필수값이 아닌경우에는 수정자 주입방식을 옵션으로 부여
- 기본으로 생성자 , 가끔 수정자 , 필드는 x
4.롬복과 최신트렌드
- 개발하면 대부분 불변
- 생성자 final 키워드를 사용하게 된다
롬복 build.gradle 추가
//lombok 설정 추가 시작
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
//lombok 설정 추가 끝
//lombok 라이브러리 추가 시작
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
//lombok 라이브러리 추가 끝
- plugin -> lombok 설치
- annotation processors -> Enable annotation processing 클릭
기본코드 OrderServiceImpl
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
//private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
롬복 OrderServiceImpl
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
//private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
}
- final 필드가 있으면 자동으로 생성자를 만들고 @Autowired 넣어준다
5.@Autowired 필드명 , @Qualifier , @Primary
- 조회대상 빈이 2개일때 해결방법
- @Autowired 필드명
- @Qualifier
- @Primary
@Autowired 필드명
@Autowired
private DiscountPolicy discountPolicy
@Autowired
private DiscountPolicy rateDiscountPolicy
- 필드명 매칭은 타입 매칭을 시도하고 결과에 여러빈이 있을경우 추가로 동작하는 기능
@Qualifier
- 추가 구분자를 붙여주는 방식 , 빈이름을 변경하는것은 아니다
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
- @Qualifier 끼리 매칭
- 빈이름 매칭
- NoSuchBeanDefinitionException 예외 발생
@Primary
- 우선순위를 정하는 방법
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
우선순위
- @Primary 는 기본값처럼 동작
- @Qualifier 는 매우 상세하게 동작하므로 우선순위를 먼저 가진다
6.자동,수동의 올바른 실무운영기준
- 편리한 자동기능을 기본으로 사용하자
- @Component 뿐만아니라 @Controller , @Service , @Repository 처럼 일반적인 애플리케이션 로직을 자동으로 스캔
- 스프링부트는 컴포넌트 스캔을 기본으로 사용
- 자동빈 등록으로도 OCP , DIP 를 지킬수 있다
수동빈 사용은 언제?
- 업무로직 빈 : 웹을 지원하는 컨트롤러 , 핵심비즈니스 로직 서비스 , 데이터 계층의 로직을 처리하는 리포지토리
- 기술지원 빈 : 데이터베이스연결, 공통로그처리업무로직 지원할때
- 업무로직 : 자동빈 등록
- 기술지원로직 : 수동빈 등록
정리
- 편리한 자동기능을 기본으로 사용
- 직접등록하는 기술지원 객체는 수동 등록
- 다형성을 적극활용하는 비즈니스 로직을 수동등록 고민
참고
728x90
'Back-End > Spring' 카테고리의 다른 글
6.컴포넌트 스캔 (0) | 2021.01.07 |
---|---|
5.싱글톤 컨테이너 (0) | 2021.01.05 |
4.스프링 컨테이너와 스프링 빈 (0) | 2021.01.04 |
3.스프링 핵심 원리 이해2 - 객체지향원리적용 (0) | 2021.01.01 |
2.스프링 핵심 원리 이해1 - 예제만들기 (0) | 2020.12.31 |