이전 글
스프링 컨테이너와 스프링 빈
스프링 컨테이너 생성
ApplicationContext = 스프링 컨테이너, 인터페이스
스프링 컨테이너는 xml, 혹은 annotation 기반 자바 설정 클래스
AnnotationConfigApplicationContext는 ApplicationContext의 인터페이스 구현체
스프링 빈의 이름은 메소드 이름 사용, 직접 부여도 가능(유니크하도록)
빈 생성 후 의존 관계 주입
컨테이너에 등록된 모든 빈 조회
applicationContext에서 getBean을 사용하여 확인
BeanDefinition에서 역할별 bean 확인 가능
import hello.core.AppConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기")
void findAllBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " object = " + bean);
}
}
@Test
@DisplayName("애플리케이션 빈 출력하기")
void findApplicationBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
// ROLE_APPLICATION : 직접 등록한 애플리케이션 빈
// ROLE_INFRASTRUCTURE : 스프링 내부에서 사용하는 빈
if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " object = " + bean);
}
}
}
}
ApplicationContextInfoTest.java
스프링 빈 조회 - 기본
ApplicationContext의 getBean() 함수 사용
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;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ApplicationContextBasicFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름으로 조회")
void findBeanByName() {
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("구체 타입으로 조회") // 유연성이 떨어짐
void findBeanByName2() {
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("이름 없이 타입으로만 조회")
void findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈 타입으로 조회 X")
void findBeanByNameX() {
// ac.getBean("xxxxx", MemberServiceImpl.class);
assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean("xxxxx", MemberServiceImpl.class));
}
}
ApplicationContextBasicFindTest.java
스프링 빈 조회 - 동일한 타입이 둘 이상
ApplicationContext의 getBeansOfType() 함수 사용
import hello.core.AppConfig;
import hello.core.discount.DiscountPolicy;
import hello.core.member.MemberRepository;
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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다.")
void findBeanByTypeDuplicate() {
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(MemberRepository.class));
}
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면, 빈 이름을 지정하면 된다.")
void findBeanByName() {
MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
assertThat(memberRepository).isInstanceOf(MemberRepository.class);
}
@Test
@DisplayName("특정 타입을 모두 조회하기")
void findAllBeanByType() {
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);
assertThat(beansOfType.size()).isEqualTo(2);
}
@Configuration
static class SameBeanConfig {
@Bean
public MemberRepository memberRepository1(){
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2(){
return new MemoryMemberRepository();
}
}
}
ApplicationContextSameBeanFindTest.java
스프링 빈 조회 - 상속 관계
Object 타입으로 조회시 모든 스프링 빈을 조회한다.
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ApplicationContextExtendsFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
@Test
@DisplayName("부모 타입으로 조회, 자식이 둘 이상이면, 중복 오류가 발생한다.")
void findBeansByParentTypeDuplicate() {
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(DiscountPolicy.class));
}
@Test
@DisplayName("부모 타입으로 조회, 자식이 둘 이상이면, 빈 이름을 지정하면 된다.")
void findBeansByParentTypeBeanName() {
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("특정 하위 타입으로 조회")
void findBeansBySubType() {
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("부모 타입으로 모두 조회하기")
void findAllBeanByParentType() {
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
assertThat(beansOfType.size()).isEqualTo(2);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
}
@Test
@DisplayName("부모 타입으로 모두 조회하기 - Object")
void findAllBeanByObjectType() {
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
}
@Configuration
static class TestConfig {
@Bean
public DiscountPolicy rateDiscountPolicy(){
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy(){
return new FixDiscountPolicy();
}
}
}
ApplicationContextExtendsFindTest.Java
BeanFactory와 ApplicationContext
beanFactory는 스프링 컨테이너의 최상위 인터페이이스
MessageSource를 이용한 국제화 기능
EnvironmentCapable을 이용한 환경 변수 관리
ApplicationEventPublisher를 이용한 이벤트를 발행하고 구독하는 모델을 편리하게 지원
ResourceLoader를 이용하여 편리한 리소스 조회
다양한 설정 형식 지원 - 자바 코드, XML
GenericXmlApplicationContext를 이용한 방법
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<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" />
</beans>
appConfig.xml
import hello.core.member.MemberService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
public class XmlApplicationContext {
@Test
void xmlAppContext() {
ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf(MemberService.class);
}
}
XmlApplicationContext.java
스프링 빈 설정 메타 정보 - BeanDefinition
BeanDefinition 정보
BeanClassName - 생성할 빈의 클래스 명
factoryBeanName - 팩토리 역할의 빈을 사용할 경우 ex) appConfig
factoryMethodName - 빈을 생성할 팩토리 메소드 ex) memberService
Scope - 싱글톤
lazyInit - 실제 빈 사용시까지 지연처리 하는지 여부
InitMethodName - 빈 생성 및 의존관계 적용 후 호출하는 초기화 메소드 명
DestoryMethodName - 생명 주기 후 제거 직전 호출되는 메소드 명
Constructor arguments, Properties - 의존 관계 주입에서 사용
import hello.core.AppConfig;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class BeanDefinitionTest {
// annotation 방식은 factory method를 이용하여 만드는 방식
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
// GenericXmlApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
@Test
@DisplayName("빈 설정 메타정보 확인")
void findApplicationBean() {
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);
}
}
}
}
BeanDefinitionTest.java
다음 글
'IT > Spring' 카테고리의 다른 글
[Spring] 스프링 핵심 원리 - 기본편 (6) (0) | 2023.03.07 |
---|---|
[Spring] 스프링 핵심 원리 - 기본편 (5) (0) | 2023.03.05 |
[Spring] 스프링 핵심 원리 - 기본편 (3) (0) | 2023.01.28 |
[Spring] 스프링 핵심 원리 - 기본편 (2) (0) | 2023.01.24 |
[Spring] 스프링 핵심 원리 - 기본편 (1) (0) | 2023.01.09 |
댓글