private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired // 생성자가 딱 1개라면 생략 가능
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired(required = false)
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired
public void setMemberRepository(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
@Autowired private MemberRepository memberRepository;
@Autowired private DiscountPolicy discountPolicy;
@Autowired
작동하지 않음 -> @SpringBootTest 처럼 스프링 컨테이너를 테스트에 통합한 경우에만 가능@Bean
에서 파라미터에 의존관계는 자동주입됨private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Autowired(required=false)
: 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출 안됨org.springframework.lang.@Nullable
: 자동 주입할 대상이 없으면 null이 입력됨Optional<>
: 자동 주입할 대상이 없으면 Optional.empty 가 입력됨롬복
라이브러리를 이용한 개발@RequiredArgsConstructor
: final이 붙은 필드를 모아 생성자 자동 생성@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
``
@Autowired
는 타입(Type)으로 조회 -> ac.getBean(DiscountPolicy.class)
과 유사한 동작@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
private final MemberRepository memberRepository;
private final DiscountPolicy rateDiscountPolicy;
@Autowired // 생성자가 딱 1개라면 생략 가능
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = rateDiscountPolicy;
}
@Qualifier
붙이기@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Qualifier("이름")
을 못찾으면, 이름
을 가진 스프링빈을 추가로 찾음@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Qualifier
@Qualifier("mainDiscountPolicy")
처럼 문자(mainDiscountPolicy)를 적으면 컴파일시 타입 체크가 안됨@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}
@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {}
public class AllBeanTest {
@Test
void findAllBean() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
DiscountService discountService = ac.getBean(DiscountService.class);
assertThat(discountService).isInstanceOf(DiscountService.class);
Member member = new Member(1L, "userA", Grade.VIP);
int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");
assertThat(discountPrice).isEqualTo(1000);
}
static class DiscountService {
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policies;
public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
this.policyMap = policyMap;
this.policies = policies;
}
public int discount(Member member, int price, String discountCode) {
DiscountPolicy discountPolicy = policyMap.get(discountCode);
return discountPolicy.discount(member, price);
}
}
}
스프링은 @Component
뿐만 아니라 @Controller
, @Service
, @Repository
처럼 계층에 맞추어 애플리케이션 로직을 자동으로 스캔할 수 있도록 지원함
설정 정보를 기반으로 애플리케이션을 구성하는 부분과 동작하는 부분을 명확하게 나누는 것이 이상적이지만, 스프링 빈 등록시 @Component만 넣어주면 끝나기 때문에 자동화 선호하는 추세
애플리케이션은 크게 업무 로직과 기술 지원 로직으로 나눌 수 있습니다.
수동 빈 등록
을 사용해서 명확하게 하는게 좋음