
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext : 스프링 컨테이너(인터페이스)new AnnotationConfigApplicationContext(AppConfig.class); : 구현체
package hello.core;
import hello.core.Discount.DiscountPolicy;
import hello.core.Discount.RateDiscountPolicy;
import hello.core.Order.OrderService;
import hello.core.Order.OrderServiceImpl;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
public class AppConfig {
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
public DiscountPolicy discountPolicy(){
return new RateDiscountPolicy();
}
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
}
new AnnotationConfigApplicationContext(AppConfig.class)
package hello.core;
import hello.core.Discount.DiscountPolicy;
import hello.core.Discount.RateDiscountPolicy;
import hello.core.Order.OrderService;
import hello.core.Order.OrderServiceImpl;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 애너테이션 추가
@Configuration
public class AppConfig {
@Bean
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy(){
return new RateDiscountPolicy();
}
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
}
@Bean(name = "memberService")로 설정도 가능
package hello.core.beanfind;
import hello.core.AppConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationBeanInfoTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기")
void findAll(){
// 스프링에 등록된 모든 빈이름 조회
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for(String beans : beanDefinitionNames){
Object bean = ac.getBean(beans);
System.out.println("name : " + beans + "Object" + bean);
}
}
}

내가 등록한 빈과 스프링 내부에서 사용하는 빈이 모두 출력된다.
package hello.core.beanfind;
import hello.core.AppConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.beans.factory.config.BeanDefinition;
public class ApplicationBeanInfoTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("애플리케이션 빈 조회")
void AppBeanFind(){
// 모든 빈이름 조회
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beans : beanDefinitionNames){
BeanDefinition beanDefinition = ac.getBeanDefinition(beans);
// 스프링 내부에서 사용하는 빈은 .getRole() 로 구분할 수 있다.
// .ROLE_APPLICATION : 사용자 정의 빈
// .ROLE_INFRANSTRUCTURE : 스프링 내부에서 사용하는 빈
if(beanDefinition.getRole()== BeanDefinition.ROLE_APPLICATION){
Object bean = ac.getBean(beans);
System.out.println("name : " + beans + "Object" + bean);
}
}
}
}

내가 등록한 빈만 조회된다.
- 빈 이름으로 조회
- 빈 타입으로 조회
- 구체화로 조회
- 빈 이름으로 조회 안되는 경우
package hello.core.beanfind;
import hello.core.AppConfig;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationBasucFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름으로 조회")
void findname(){
MemberService memberService1 = ac.getBean("memberService", MemberService.class);
Assertions.assertThat(memberService1).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈 타입으로 조회")
void findtype(){
MemberService memberService1 = ac.getBean(MemberService.class);
Assertions.assertThat(memberService1).isInstanceOf(MemberServiceImpl.class);
}
// 구체화로 조회하는 것은 좋지 않은 예제이다
// 유연성이 떨어짐
@Test
@DisplayName("구체화로 조회")
void findtype2(){
MemberServiceImpl memberService1 = ac.getBean(MemberServiceImpl.class);
Assertions.assertThat(memberService1).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈 이름으로 조회 안되는 경우")
void notfindname(){
// MemberService xxxx = ac.getBean("XXXX", MemberService.class);
org.junit.jupiter.api.Assertions.assertThrows(NoSuchBeanDefinitionException.class, ()->ac.getBean("XXXX", MemberService.class));
}
}
- 중복된 타입으로 조회하기
- 특정 타입을 모두 조회하기
package hello.core.beanfind;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class ApplicationBeanDupTest {
@Configuration
static class AppConfigEX{
@Bean
public MemberRepository memberRepository1(){
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2(){
return new MemoryMemberRepository();
}
}
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfigEX.class);
@Test
@DisplayName("중복된 타입으로 조회하기")
void dupFindAll(){
MemberRepository bean = ac.getBean(MemberRepository.class);
}
}

예외가 발생한다! 코드를 수정해보자
@Test
@DisplayName("중복된 타입으로 조회하기")
void dupFindAll(){
Assertions.assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(MemberRepository.class));
}

package hello.core.beanfind;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
public class ApplicationBeanDupTest {
@Configuration
static class AppConfigEX{
@Bean
public MemberRepository memberRepository1(){
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2(){
return new MemoryMemberRepository();
}
}
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfigEX.class);
@Test
@DisplayName("중복된 타입으로 조회하기")
void dupFindAll(){
Assertions.assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(MemberRepository.class));
}
@Test
@DisplayName("특정 타입을 모두 조회하기")
void typeAll(){
// .getBeansOfType 특정 타입을 모두 조회
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
for(String key : beansOfType.keySet()){
System.out.println("key : " + key + " value : " + beansOfType.get(key) );
}
org.assertj.core.api.Assertions.assertThat(beansOfType.size()).isEqualTo(2);
}
}

- 부모 타입으로 조회 시, 자식이 둘 이상 있으면?
- 부모 타입으로 조회 시, 자식이 둘 이상 있으면 이름을 지정해주자!
- 특정 하위 타입으로 조회
- 부모 타입으로 모두 조회하기
- 부모(Object) 타입으로 모두 조회하기
package hello.core.beanfind;
import hello.core.AppConfig;
import hello.core.Discount.DiscountPolicy;
import hello.core.Discount.FixedDiscountPolicy;
import hello.core.Discount.RateDiscountPolicy;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
public class ApplicationExtendsFindTest {
@Configuration
static class AppConfigEx{
@Bean
public DiscountPolicy rateDiscountPolicy(){
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy(){
return new FixedDiscountPolicy();
}
}
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfigEx.class);
@Test
@DisplayName("부모 타입으로 조회 시, 자식이 둘 이상 있으면?")
// NoUniqueBeanDefinitionException 오류가 발생됨
void findParentType(){
Assertions.assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(DiscountPolicy.class));
}
@Test
@DisplayName("부모 타입으로 조회 시, 자식이 둘 이상 있으면 이름을 지정해주자!")
void findParentType1(){
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
DiscountPolicy fixDiscountPolicy = ac.getBean("fixDiscountPolicy", DiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(fixDiscountPolicy).isInstanceOf(FixedDiscountPolicy.class);
}
@Test
@DisplayName("특정 하위 타입으로 조회")
void findchildType(){
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
org.assertj.core.api.Assertions.assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("부모 타입으로 모두 조회하기")
void findParentAll(){
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
for(String key : beansOfType.keySet()){
System.out.println("key : " + key + " value : " + beansOfType.get(key));
}
org.assertj.core.api.Assertions.assertThat(beansOfType.size()).isEqualTo(2);
}
@Test
@DisplayName("부모(Object) 타입으로 모두 조회하기")
void findParentAllobj(){
Map<String, Object> beansOfType1 = ac.getBeansOfType(Object.class);
for(String key : beansOfType1.keySet()){
System.out.println("key : " + key + " value : " + beansOfType1.get(key));
}
// org.assertj.core.api.Assertions.assertThat(beansOfType1.size()).isEqualTo(16);
}
}

Object 타입으로 조회 시 내장되어 있는 빈들 모두 조회된다.