728x90
컨테이너에 등록된 모든 빈 조회
package springConquest.core.findBean;
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;
import springConquest.core.AppConfig;
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);
}
}
더보기
티끌 모아 먼지 꿀팁 (단축키)
위에 beanDefinitionNames 같은 리스트가 있을 때
iter 하고 tab을 하게 되면 자동으로 for문을 생성해 준다!
그리고 print문 찍을 때 soutm을 하고 자동완성을 하면 메서드명 print문이 만들어지고, soutv는 변수명 print문이 만들어진다.
// 출력 결과
name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor object = org.springframework.context.annotation.ConfigurationClassPostProcessor@56c4278e
name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor object = org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@41ab013
name = org.springframework.context.annotation.internalCommonAnnotationProcessor object = org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@14bee915
name = org.springframework.context.event.internalEventListenerProcessor object = org.springframework.context.event.EventListenerMethodProcessor@1115ec15
name = org.springframework.context.event.internalEventListenerFactory object = org.springframework.context.event.DefaultEventListenerFactory@82ea68c
name = appConfig object = springConquest.core.AppConfig$$EnhancerBySpringCGLIB$$68173554@59e505b2
name = memberService object = springConquest.core.member.MemberServiceImpl@3af0a9da
name = memberRepository object = springConquest.core.member.MemoryMemberRepository@43b9fd5
name = orderService object = springConquest.core.order.OrderServiceImpl@79dc5318
name = discountPolicy object = springConquest.core.discount.RateDiscountPolicy@8e50104
이렇게 직접 등록한 빈 말고도 스프링 자체 빈도 출력된다.
@Test
@DisplayName("애플리케이션 빈 출력하기")
void findApplicationBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
//beanDefinition : bean의 메타데이터 정보
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
//Role ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
//Role ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " object = " + bean);
}
}
}
정리
- 모든 빈 출력하기
ac.getBeanDefinitionNames(): 스프링에 등록된 모든 빈 이름을 조회한다.
ac.getBean(): 빈이름으로 빈 객체(인스턴스)를 조회한다. - 애플리케이션 빈 출력하기
스프링 내부에서 사용하는 빈을 제외하고, 내가 등록한 빈만 출력 ➜
스프링 내부에서 사용하는 빈은 getRole()로 구분할 수 있다.
- ROLE_APPLICATION: 일반적으로 사용자가 정의한 빈
- ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
스프링 빈 조회 - 기본
스프링 컨테이너에서 스프링 빈을 찾는 가장 기본적인 조회 방법
- ac.getBean(빈이름, 타입)
- ac.getBean(타입)
package springConquest.core.findBean;
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 springConquest.core.AppConfig;
import springConquest.core.member.MemberService;
import springConquest.core.member.MemberServiceImpl;
import static org.assertj.core.api.Assertions.assertThat;
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 findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("구체 타입으로 조회")
void findBeanByName2() {
MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
// 실패 테스트 작성하는 습관 기르기
@Test
@DisplayName("빈 이름으로 조회 실패")
void findByNameX() {
//ac.getBean("XXX", MemberService.class);
assertThrows(NoSuchBeanDefinitionException.class, () -> ac.getBean("XXX", MemberService.class));
}
이런 식으로 빈 이름과 타입으로 기본적인 빈 조회방법을 테스트 코드를 통해 알아봤다.
스프링 빈 (약) 심화
빈 조회에서 상속 관계
부모 타입으로 조회하면, 자식 타입도 함께 조회한다. (그래서 모든 자바 객체의 최고 부모인 Object타입으로 조회하면, 모든 스프링 빈을 조회한다.)
BeanFactory와 ApplicationContext
BeanFactory
스프링 컨테이너의 최상위 인터페이스다.
스프링 빈을 관리하고 조회하는 역할을 담당한다.
getBean()을 제공한다.
지금까지 우리가 사용했던 대부분의 기능은 BeanFactory가 제공하는 기능이다.
ApplicationContext
기능을 모두 상속받아서 제공한다.
빈을 관리하고 검색하는 기능을 BeanFactory가 제공해 주는데, 그러면 둘의 차이가 뭘까?
애플리케이션을 개발할 때는 빈을 관리하고 조회하는 기능은 물론이고, 수많은 부가기능이 필요하다.
정리
ApplicationContext는 BeanFactory의 기능을 상속받는다.
ApplicationContext는 빈 관리기능 + 편리한 부가 기능을 제공한다.
BeanFactory를 직접 사용할 일은 거의 없다. 부가기능이 포함된 ApplicationContext를 사용한다.
BeanFactory나 ApplicationContext를 스프링 컨테이너라 한다.
이와 같이 빈에 대한 깊은 내용은 간단하게 정리하고 넘어가겠다.
인프런에서 진행한 김영한 님의 강의(스프링 핵심 원리 - 기본 편)를 토대로 정리한 포스팅입니다.
자세한 내용은 링크를 참고하시기 바랍니다. 문제시 바로 삭제하겠습니다.
728x90