ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext
를 스프링 컨테이너라 하며, 인터페이스다.ApplicationContext
의 구현체는 여러가지가 있다.(XML기반, 어노테이션 기반)AppConfig
를 사용했던 방식이 어노테이션 기반의 자바 설정 클래스로 스프링 컨테이너를 만든 것이다.new AnnotationConfigApplicationContext(AppConfig.class)
를 통해 스프링 컨테이너를 생성한다.AppConfig.class
를 구성정보로 지정하였다.ApplicationContext
)는 생성자의 파라미터로 넘어온 설정 클래스의 정보를 사용하여 스프링 빈을 등록한다.AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
Object bean = ac.getBean(beanDefinitionName);
ac.getBeanDefinitionNames()
을 통해 스프링에 등록된 모든 빈 이름을 문자열 배열로 반환한다.ac.getBean()
에 매개변수로 전달된 빈 이름으로 빈 객체(인스턴스)를 조회한다.AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
beanDefinition.getRole()
}
// BeanDefinition.ROLE_APPLICATION
// BeanDefinition.ROLE_INFRASTRUCTURE
ac.getBeanDefinition(beanDefinitionName)
을 통해 매개변수로 전달된 빈에 대한 메타데이터 정보들을 가져온다.beanDefinition.getRole()
을 통해 빈의 role정보를 가져온다BeanDefinition.ROLE_APPLICATION
: 직접 등록한 빈BeanDefinition.ROLE_INFRASTRUCTURE
: 스프링이 내부적으로 확장하기 위한 기반 빈스프링 컨테이너에서 스프링 빈을 찾는 가장 기본적인 조회 방법
ac.getBean(빈이름, 타입)
ac.getBean(타입)
NoSuchBeanDefinitionException: No bean named 'xxxxx' available
공통 코드
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
ac.getBean(빈이름, 타입)
의 형태로 빈을 조회한다."memberService"
이며, 타입은 MemberService.class
로 구현체가 아닌, 인터페이스를 전달하였다.MemberServiceImpl
클래스가 맞는지 확인한다.DiscountPolicy discountPolicy = ac.getBean("discountPolicy", DiscountPolicy.class);
assertThat(discountPolicy).isInstanceOf(FixDiscountPolicy.class);
name = discountPolicy object = hello.core.discount.RateDiscountPolicy@2c7b5824
discountPolicy
는 RateDiscountPolicy
다. isInstanceOf(FixDiscountPolicy.class)
로 조회할 경우, 다음과 같은 오류가 발생한다.java.lang.AssertionError:
Expecting actual: hello.core.discount.RateDiscountPolicy@3b7ff809
to be an instance of: hello.core.discount.FixDiscountPolicy
but was instance of: hello.core.discount.RateDiscountPolicy
discountPolicy
는 RateDiscountPolicy
이며, RateDiscountPolicy
의 인스턴스여야 하지만, FixDiscountPolicy
의 인스턴스라 예상하여 오류가 발생하였다.MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
ac.getBean(타입)
의 형태로 빈을 조회한다.MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
ac.getBean(빈이름, 타입)
의 형태로 조회를 하나, 타입에 인터페이스가 아닌, 구현체가 전달된다.import static org.junit.jupiter.api.Assertions.assertThrows;
assertThrows(NoSuchBeanDefinitionException.class,
()->ac.getBean("xxxxx", MemberService.class));
NoSuchBeanDefinitionException
예외가 발생하여야 Test가 통과다.ac.getBean(타입)
의 형태로 빈을 조회할 경우, 같은 타입의 스프링 빈이 둘 이상일 경우 오류가 발생한다. 따라서 같은 타입의 스프링 빈이 둘 이상일 경우 빈의 이릅을 지정하여 ac.getBean(빈이름, 타입)
의 형태로 조회를 한다.
공통 코드
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Configuration
static class SameBeanConfig{
@Bean
public MemberRepository memberRepository1(){
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2(){
return new MemoryMemberRepository();
}
}
// error
MemberRepository bean = ac.getBean(MemberRepository.class)
MemberRepository
이다.NoUniqueBeanDefinitionException
에러가 발생한다.expected single matching bean but found 2: memberRepository1,memberRepository2
import static org.junit.jupiter.api.Assertions.assertThrows;
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(MemberRepository.class));
assertThrows
를 사용하여 진행한다.MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
assertThat(memberRepository).isInstanceOf(MemberRepository.class);
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
ac.getBeansOfType()
를 사용하여 스프링 컨테이너 내에 매개변수로 전달된 타입의 모든 빈을 Map
의 형태로 반환한다.Map
의 key는 빈의 이름(메소드의 이름)이며, value는 생성된 인스턴스이다.공통코드
@Configuration
static class TestConfig {
@Bean
public DiscountPolicy rateDiscountPolicy() {
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy() {
return new FixDiscountPolicy();
}
}
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
DiscountPolicy
)를 갖는 빈 2개를 생성한 후, 해당 클래스를 컨테이너의 구성정보로 사용한다.// error
DiscountPolicy bean = ac.getBean(DiscountPolicy.class);
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(DiscountPolicy.class));
DiscountPolicy
) 클래스로 조회할 경우, 2개 이상의 자식이 있으므로, NoUniqueBeanDefinitionException
이 발생한다.assertThrows
를 사용하여 Test를 실행한다.DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
ac.getBeansOfType()
메소드를 사용하여, 모든 빈을 조회한다.Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
getBean()
을 제공한다.BeanFactory
의 기능을 모두 상속받아서 제공한다.public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {...}
ApplicationContext
의 선언 코드다.BeanFactory
만 상속 받는 것이 아닌, 여러가지 부가기능을 위한 인터페이스를 상속받는 것을 알 수 있다.AnnotationConfigApplicationContext
클래스를 사용하여, 자바코드로 된 설정정보를 넘기면 된다.GenericXmlApplicationContext
를 사용하면서 xml 설정 파일을 넘기면 된다ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
appConfig.xml
이라는 xml파일 형식의 설정파일을 컨테이너에 전달하고있다.<bean id="memberService" class="hello.core.member.MemberServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository"/>
</bean>
<bean id="memberRepository" class="hello.core.member.MemoryMemberRepository"/>
<bean id="orderService" class="hello.core.order.OrderServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository"/>
<constructor-arg name="discountPolicy" ref="discountPolicy"/>
</bean>
<bean id="discountPolicy" class="hello.core.discount.RateDiscountPolicy"/>
<bean>
이라는 태그를 사용하며, @Bean
어노테이션과 같은 역할을 한다.id
라는 속성으로 빈에 이름을 부여한다.ref
라는 속성으로, 해당 빈에대한 구현의 위치를 명시한다.<constructor-arg>
라는 태그를 사용하여 해당 빈의 생성자에 배개변수를 전달한다.BeanDefinition
을 빈 설정 메타정보라 한다@Bean
, <bean>
당 각각 하나씩 메타 정보가 생성된다BeanDefinition
에만 의존한다.AnnotationConfigApplicationContext
는 AnnotatedBeanDefinitionReader
를 사용해서 AppConfig.class
를 읽고 BeanDefinition
을 생성한다.GenericXmlApplicationContext
는 XmlBeanDefinitionReader
를 사용해서 appConfig.xml
를 읽고 BeanDefinition
을 생성한다.AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
System.out.println("beanDefinitionName = " + beanDefinitionName + " beanDefinition" + beanDefinition);
}
}
ac.getBeanDefinitionNames()
을 통해 스프링에 등록된 모든 빈 이름을 문자열 배열로 반환한다.ac.getBeanDefinition()
을 통해 BeanDefinition
을 가져온다.Root bean: class [null];
scope=;
abstract=false;
lazyInit=null;
autowireMode=3;
dependencyCheck=0;
autowireCandidate=true;
primary=false;
factoryBeanName=appConfig;
factoryMethodName=memberService;
initMethodName=null;
destroyMethodName=(inferred);
defined in hello.core.AppConfig
<bean id="discountPolicy" class="hello.core.discount.RateDiscountPolicy"/>
BeanDefinition
의 factoryBeanName, factoryMethodName의 값이 null
이 된다.@Bean
public MemberService memberService(){...}
AppConfig
가 제공하는 memberService
팩토리 메소드를 사용하여 스프링 빈을 등록출처: 인프런 스프링 핵심 원리 - 기본편 (김영한)
인프런 스프링 핵심 원리