[스프링 기본] 스프링 컨테이너와 빈

마코레·2022년 4월 26일
0

백엔드개발

목록 보기
11/18

🤗 인프런 [스프링 핵심원리-기본편]을 듣고 기록하는 글입니다

스프링 컨테이너


생성방법

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  • ApplicationContext를 스프링 컨테이너라고 부르며, interface임(다형성)
  • annotation 기반으로 설정 클래스 만들기 가능
  • AnnotationConfigApplicationContext는 ApplicationContext의 구현체

스프링 컨테이너라고 한다면 사실 BeanFactory, ApplicationContext 두가지고 구분이 가능한데, 일반적으로는 ApplicationContext를 많이쓰고 BeanFactory를 직접 쓰는일은 없음


실제 진행과정

  1. 컨테이너 생성
  2. 스프링 빈 등록
    • 컨테이너는 파라미터로 넘어온 class 정보를 이용해서
    • 스프링빈을 스프링 빈 저장소에 등록함
  3. 스프링 빈 의존관계 설정-준비
    • 빈을 생성하는 단계
  4. 스프링 빈 의존관계 설정-완료
    - 설정정보를 참고해서 빈 사이의 의존관계를 주입
    - 자바코드를 그냥 호출하는것 같지만, 차이가 있다고하고, singleton container에서 설명해주신다고함

    원래 spring으로 그냥 하면 빈 생성 후, 빈 의존관계 설정이 이루어지는데, 그림처럼 우리가 직접 java코드로 빈을 생성하면 생성과 의존관계 설정이 한꺼번에 됨.
    왜냐하면 빈 생성하려고 함수 호출하면 거기안에 의존관계 설정 코드도 들어있기 때문임


스프링 빈


빈 조회 방법

  • 조회하는 test 코드

    //컨테이너 생성
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    
        @Test
        @DisplayName("모든 빈 출력하기")
         void findAllBean() {
            //컨테이너를 이용해서 bean이름을 가져오고, 그걸 배열에 담기
            String[] beanDefinitionNames = ac.getBeanDefinitionNames();
            //배열 속 bean 하나씩 출력하기
            for(String beanDefinitionName : beanDefinitionNames) {
                Object bean = ac.getBean(beanDefinitionName);
                System.out.println("name = " + beanDefinitionName + " object= " + bean);
            }
    
        }

  • 조회결과:
    - 위에 있는 bean은 스프링이, 스프링 내부 확장을 위해 자체적으로 쓰는것
    • 밑에 4개가 우리가 등록한 bean임
  • 스프링 내부 bean빼고 내꺼만 보는 방법

-스프링 내부 bean만 보는법
- BeanDefinition.ROLE_INFRASTRUCTURE쓰면됨

스프링 빈 조회 - 기본방법

  • ac.getBean(빈이름, 타입)

  • ac.getBean(타입)

  • 스프링빈이 없으면 예외발생

  • 조회 성공 test:
    - 조회하는 방식에서, 타입으로 interface말고 구체class를 넣어도 동작함. 그러나 이런식으로 조회하면, 유연성이 떨어지므로 잘 안쓴다는점 알아두기!

  • 조회 실패 test:

스프링 빈 조회 - 동일타입 둘 이상

  • ac.getBeansOfType()를 사용하면 해당 타입의 모든 빈을 조회할 수 있음

  • 중복 타입 만들기 위해서, 간이로 test안에 config class생성함 :

    @Configuration
        static class SameBeanConfig {
            //간이로 만든 class니까 지금 이 text class안에서만 이 class를 쓰겠다는 의미로 static으로 선언한거임
            //그리고, appconfig에는 중복타입이 없으니까 test가 안돼서, 지금 새로 만드는거임
            //이런식으로 중복으로 만드는경우 있음. 예를들어 반환 파라미터가 다르다든가 ㅇㅇ
            @Bean
            public MemberRepository memberRepository1() {
                return new MemoryMemberRepository();
            }
    
            @Bean
            public MemberRepository memberRepository2() {
                return new MemoryMemberRepository();
            }
        }

  • test fail :

    @Test
        @DisplayName("타입으로 조회 시 같은 타입이 둘 이상이면, 중복 오류가 발생한다")
        void findBeanByTypeDuplicate() {
            MemberRepository bean = ac.getBean(MemberRepository.class);
        }


  • 오류발생시 test는 성공하도록 코드 변경해서 살펴보기 :

    @Test
        @DisplayName("타입으로 조회 시 같은 타입이 둘 이상이면, 중복 오류가 발생한다")
        void findBeanByTypeDuplicate() {
            Assertions.assertThrows(NoUniqueBeanDefinitionException.class,
                    () -> ac.getBean(MemberRepository.class));
        }

  • 중복일때 하나만 잘 찾는법 = 이름으로! :

    @Test
        @DisplayName("타입으로 조회 시 같은 타입이 둘 이상 있으면, 빈 이름을 지정하면 된다")
        void findBeanByName() {
            MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
            org.assertj.core.api.Assertions.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);
            org.assertj.core.api.Assertions.assertThat(beansOfType.size()).isEqualTo(2);
        }

스프링 빈 조회 - 상속관계

  • 스프링 빈 조회 시, 만약 자식이 있다면 자식 타입도 함께 조회됨

  • config class에서 bean 만들때 rateDiscountPolicy bean의 타입을 rateDiscountPolicy로 안하고 DiscountPolicy로 함수 선언해놓는 이유는?

    • 역할과 구현을 항상 나누는것과 같은 이유
    • 이 bean이 discountpolicy다 라는것을 알려주는거기도 하고
    • 의존성 주입할때도 타입이 discountpolicy니까 구현체가 아닌 역할에 의존하게됨.
  • 원래는 테스트 코드에 이런식으로 출력같은거 넣지 않음

    • 통과 실패는 원래 시스템이 정하기 때문에 그거로만 판단하고, 주로 출력문을 넣지는 않음
  • bean 조회는 이정도만 알면됨

  • 사실 applicationContext에서 getBean할일 없음. spring Container가 자동으로 의존관계 주입해주는거 씀.

profile
새싹 백엔드 개발자

0개의 댓글