public class applicationContextInfoTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기")
void finaAllBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("bean = " + beanDefinitionName + " object = " + bean);
}
}
@Test
@DisplayName("애플리케이션 빈 출력하기") // 내가 등록한 빈만 출력하기
void finaApplicationBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
// ROLE_APPLICATION : 직접 등록한 애플리케이션 빈
// ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈
if(beanDefinition.getRole() == BeanDefinition.ROLE_INFRASTRUCTURE){
Object bean = ac.getBean(beanDefinitionName);
System.out.println("bean = " + beanDefinitionName + " object = " + bean);
}
}
}
}
모든 빈 출력하기직접 등록한 애플리케이션 빈
스프링 빈 조회 - 기본
스프링 컨테이너에서 스프링 빈을 찾는 가장 기본적인 조회 방법
ac.getBean(빈 이름 , 타입)
ac.getBean(타입)
조회 대상 스프링 빈이 없으면 예외 발생
NoSuchBeanDefinitionException : No Bean name 'xxxxx' available
Ctrl + E - 최근 작성 또는 수정한 코드 조회
ApplicationContextBeanBasicFindTest
class ApplicationContextBeanBasicFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름으로 조회")
void 빈_이름으로_조회(){
MemberService memberService = ac.getBean("memberService", MemberService.class);
// getBean으로 찾아온 MemberService와 실제 객체가 연결된 구현체(MemberServiceImpl)과 동일한지
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("이름없이 타입으로만 조회")
void 이름없이_타입으로만_조회(){
MemberService memberService = ac.getBean(MemberService.class);
// getBean으로 찾아온 MemberService와 실제 객체가 연결된 구현체(MemberServiceImpl)과 동일한지
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("구현체 타입으로 조회")
void 구현체_타입으로_조회(){
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈 이름으로 조회(예외)")
void 빈_이름으로_조회_예외(){
// ac.getBean 실행 시 예외가 터져야 테스트 정상 완료
org.junit.jupiter.api.Assertions.assertThrows(NoSuchBeanDefinitionException.class
, () -> ac.getBean("xxxx" ,MemberService.class));
}
}
스프링 빈 조회 - 동일한 타입이 둘 이상
org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'hello.core.member.MemberRepository' available:
expected single matching bean but found 2: memberRepository1,memberRepository2
타입으로 조회시 같은 타입의 스프링 빈이 둘 이상이면 오류가 발생한다. 이때는 빈 이름을 지정하자.
ac.getBeansOfType()을 사용하면 해당 타입의 모든 빈을 조회할 수 있다.
ApplicationContextSameBeanFindTest
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Configuration
static class SameBeanConfig {
@Bean
public MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면 , 중복 오류가 발생한다.")
void 같은_타입_둘_이상_조회() {
Assertions.assertThrows(NoUniqueBeanDefinitionException.class
, () -> ac.getBean(MemberRepository.class));
}
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면 , 빈 이름을 지정하면 된다.")
void 빈_이름_조회() {
MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
org.assertj.core.api.Assertions.assertThat(memberRepository).isInstanceOf(MemberRepository.class);
}
@Test
@DisplayName("특정 타입을 모두 조회하기")
//Ctrl + Shift + Enter - 코드 컴플리션
void 빈_타입_조회(){
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
System.out.println("beansOfType = " + beansOfType);
org.assertj.core.api.Assertions.assertThat(beansOfType.size()).isEqualTo(2);
}
// key = memberRepository1 value = hello.core.member.MemoryMemberRepository@550a1967
// key = memberRepository2 value = hello.core.member.MemoryMemberRepository@2a640157
// beansOfType = {memberRepository1=hello.core.member.MemoryMemberRepository@550a1967, memberRepository2=hello.core.member.MemoryMemberRepository@2a640157}
}
스프링 빈 조회 - 상속 관계
부모 타입으로 조회하면 , 자식 타입도 함게 조회한다.
그래서 모든 자바 객체의 최고 부모인 Object타입으로 조회하면 , 모든 스프링 빈을 조회한다.
public class ApplicationContextExtendsFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
@Configuration
static class TestConfig{
@Bean
public DiscountPolicy rateDiscountPolicy(){
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy(){
return new FixDiscountPolicy();
}
}
@Test
@DisplayName("부모 타입으로 조회시 , 자식이 둘 이상 있으면 , 중복 오류가 발생한다.")
void 부모_타입_조회(){
Assertions.assertThrows(NoUniqueBeanDefinitionException.class
, () -> ac.getBean(DiscountPolicy.class));
}
@Test
@DisplayName("부모 타입으로 조회시 , 자식이 둘 이상 있으면 , 빈 이름을 지정하면 된다..")
void 부모_타입_조회_빈_이름_지정(){
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("특정 하위 타입으로 조회")
void 특정_하위_타입_조회(){
RateDiscountPolicy rateDiscountPolicy = ac.getBean(RateDiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("부모 타입으로 모두 조회")
void 부모_타입_모두_조회(){
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(beansOfType.size()).isEqualTo(2);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
// key = rateDiscountPolicy value = hello.core.discount.RateDiscountPolicy@58ffcbd7
// key = fixDiscountPolicy value = hello.core.discount.FixDiscountPolicy@555cf22
}
@Test
@DisplayName("Object 타입으로 모두 조회")
void Object_타입(){
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
// 스프링에 등록된 모든 빈 출력
}
}
조회한 빈이 모두 필요할 때 List , Map
의도적으로 정말 해당 타입의 스프링 빈이 다 필요한 경우도 있다.
할인 서비스를 제공하는데 , 클라이언트가 할인의 종류 (rate,fix)를 선택할 수 있다고 가정해보자.스프링을 사용하면 소위 말하는 전략 패턴을 매우 간단하게 구현할 수 있다.
스프링 빈 조회
빈 출력 해보기
ApplicationContextInfoTest
스프링 빈 조회 - 기본
ApplicationContextBeanBasicFindTest
스프링 빈 조회 - 동일한 타입이 둘 이상
ApplicationContextSameBeanFindTest
스프링 빈 조회 - 상속 관계
조회한 빈이 모두 필요할 때 List , Map
의도적으로 정말 해당 타입의 스프링 빈이 다 필요한 경우도 있다.
할인 서비스를 제공하는데 , 클라이언트가 할인의 종류 (rate,fix)를 선택할 수 있다고 가정해보자.스프링을 사용하면 소위 말하는 전략 패턴을 매우 간단하게 구현할 수 있다.
인터페이스 - DiscountPolicy
구현체 - FixDiscountPolicy(VIP는 1000원 고정 할인) , RateDiscountPolicy (VIP는 금액의 10% 할인)
FixDiscountPolicy
RateDiscountPolicy
생성자의 출력 결과
로직 분석
스프링 핵심 원리 - 기본편 - 인프런
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 초급 프레임워크 및 라이브러리 웹 개발 서버 개발 Back-End Spring 객체지향 온
www.inflearn.com
'스프링 핵심 원리 > 스프링 컨테이너와 스프링 빈' 카테고리의 다른 글