Search
Duplicate
📒

[Spring Study] 03-1. 스프링 컨테이너, 빈 등록/조회, 컴포넌트 스캔

상태
완료
수업
Spring Study
주제
Bean
4 more properties
참고

스프링 컨테이너의 생성 및 관리

NOTE
스프링 컨테이너는 스프링의 빈(bean) 생성, 관리, 조회 등을 담당하는 객체입니다. 이는 XML 또는 애노테이션 기반의 자바 설정 클래스로 구성될 수 있습니다.
// 스프링 컨테이너 생성 ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
Java
복사
스프링 컨테이너는 BeanFactoryApplicationContext 두 종류의 인터페이스로 구현되어 있습니다. 일반적으로 스프링 컨테이너는 ApplicationContext를 사용합니다.
BeanFactory는 스프링의 기본적인 IOC 컨테이너이며 빈의 등록/생성/조회를 관리하며 getBean() 메서드를 통해 빈을 인스턴스화 할 수 있습니다.
BeanDefinition을 통한 Bean생성
ApplicationContext는 BeanFactory의 기능을 상속받아 제공해주며, BeanFactory의 기능 이외의 부가 기능을 제공해줍니다. 아래는 부가 기능의 종류입니다.
ApplicationContext는 여러 인터페이스를 상속받아서 국제화, 이벤트, 리소스 조회 등의 기능을 제공한다
MessageSource(메시지 다국화 인터페이스)
ApplicationEvenePublisher(이벤트 관련 기능)
ResourceLoader(파일, 클래스 등 리소스 조회)

@Configuration 빈 등록

NOTE
스프링 컨테이너는 스프링 설정 클래스(@Configuration)에서 빈을 등록할 수 있습니다. 기본적으로 메서드 이름을 사용하지만 @Bean(name=”customName”)으로 명시적으로 부여할 수도 있습니다.
@Configuration public class AppConfig { // 이름으로 명시가능 @Bean(name = "memberService") public MemberService memberService() { return new MemberServiceImpl(memberRepository()); } @Bean public OrderService orderService() { return new OrderServiceImpl( memberRepository(), discountPolicy() ); } @Bean public MemberRepository memberRepository() { return new MemoryMemberRepository(); } @Bean public DiscountPolicy discountPolicy() { return new RateDiscountPolicy(); } }
Java
복사
AppConfig.class 등록
@Bean이름 - Bean 객체로 저장된다.
AppConfig를 참조해 의존관계를 주입(DI)한다!

@ComponentScan 빈 등록

NOTE
스프링은 @ComponentScan 어노테이션을 사용해서 지정된 패키지 및 하위 패키지를 탐색하여 @Component가 붙은 클래스를 찾아 자동으로 빈에 등록해줍니다.
@Component public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository; // 자동으로 주입시켜준다. @Autowired public MemberServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } } @Component public class MemoryMemberRepository implements MemberRepository {}
Java
복사
스프링 부트를 사용할 경우, 기본적으로 @SpringBootApplication이 등록되어 있고, 이 내부에는 @ComponentScan이 포함되어 있습니다.
// basePackage: 해당 경로부터 하위 패키지를 모두 검색합니다. @ComponentScan( basePackages = "hello.core" )
Java
복사
스프링 부트를 실행시키면 자동으로 빈이 등록됨
스프링 부트를 실행하면 자동으로 빈이 등록됩니다.
스프링은 다음과 같은 어노테이션도 기본 스캔 대상에 포함합니다. 참고로 각 어노테이션은 내부에 @Component를 가지고 있습니다. 이 어노테이션들은 컴포넌트 스캔의 대상이 되면서 추가적인 기능들을 수행합니다.
@Controller: MVC 컨트롤러로 인식합니다.
@Service: 비즈니스 로직을 처리하는 서비스 레이어로 인식합니다.
@Repository : 데이터 계층의 예외를 스프링 예외로 반환합니다.
@Configuration: 설정 정보로 인식하고, 빈 정의를 담당합니다.

컨테이너에 등록된 빈 조회

NOTE
@Test void findApplicationBean(){ String[] beanDefinitionNames = ac.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { // Bean의 메타데이터 BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName); // 내가 등록한 Bean // BeanDefinition.ROLE_APPLICATION : 직접 등록한 애플리케이션 빈 // BeanDefinition.ROLE_INFRASTRUCTURE : 스프링 내부에서 사용하는 빈 if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){ Object bean = ac.getBean(beanDefinitionName); System.out.println("beanDefinitionName = " + beanDefinitionName + " object = " + bean); } } }
Java
복사
스프링 빈 조회 - 전체
@Test void findBean() { // 이름 조회 MemberService memberService = ac .getBean("memberService", MemberService.class); assertThat(memberService).isInstanceOf(MemberServiceImpl.class); // 타입 조회 MemberService memberService = ac .getBean(MemberService.class); assertThat(memberService).isInstanceOf(MemberServiceImpl.class); }
Java
복사
스프링 빈 조회 - 이름

동일 타입 빈이 2개인 경우

@Configuration static class SameBeanConfig { @Bean public MemberRepository memberRepository1() { return new MemoryMemberRepository(); } @Bean public MemberRepository memberRepository2() { return new MemoryMemberRepository(); } }
Java
복사
임시로 MemberRepository 타입 빈이 2개있는 설정파일 생성
@Test void findBeanByTypeDuplicate(){ assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(MemberRepository.class)); }
Java
복사
NoUniqueBeanDefinitionException 이 발생 (1개를 기대했는데 2개나옴)
실제 발생에러
@Test void findBeanByName(){ // 빈 이름으로 타입을 구분해서 조회한다. MemberRepository memberRepository = ac .getBean("memberRepository1",MemberRepository.class); assertThat(memberRepository).isInstanceOf(MemberRepository.class); }
Java
복사
타입으로 조회 시, 같은 타입이 2개 이상 있으면 빈 이름을 지정하면 된다!
@Test void findAllBeanByType(){ // getBeansOfType() => Map<이름, 타입> 으로 전체조회 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); }
Java
복사
getBeansOfType() 메서드로 MAP<이름, 타입> 특정 타입의 모든 빈을 조회 할 수 있다