성장일기

내가 보려고 정리하는 공부기록

백엔드/스프링

[Spring] 2. 스프링으로 전환하기 (스프링 빈, 스프링 컨테이너) - 스프링 핵심원리 기본편

와나나나 2024. 2. 5. 21:55
728x90

인프런 김영한 강사님의 스프링 핵심원리 강의를 듣고 정리하고자 한다. 목차는 다음과 같다.

  • 스프링 컨테이너와 스프링 빈
  • 스프링 빈 조회

1. 스프링 컨테이너와 스프링 빈

지난 게시글에서는 순수한 자바 코드를 이용해서 DI를 적용했다. 

 

/ import 생략

@Configuration
public class AppConfig {
	
    @Bean
	public MemberService memberService() {
    	return new MemberServiceImpl(memberRepository());
    }
    
    @Bean
    public OrderService orderService() {
    	return new OrderServiceImpl(
        	memberRepository(),
            discountPolicy());
    }
    
    @Bean
    ppublic MemberRepository memberRepository() {
    	return new MemoryMemberRepository();
    }
    
    @Bean
    public DiscountPolicy discountPolicy() {
    	return new FixDiscountPolicyy();
    }

}

 

지난 코드와 차이가 보이는가 ? AppConfig에는 @Configuration을, 각 메소드에 @Bean을 붙여주었다. 

 

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);

 

위 두 코드에서 쓰인 @Configuration, @Bean, ApplicationContext, new AnnotationConfigApplication을 설명하면 다음과 같다.

 

✅ 스프링 컨테이너 

 

ApplicationContext를스프링 컨테이너라고 한다.  기존에는 개발자가 AppConfig로 직접 객체 생성, DI를 했지만 이젠 스프링 컨테이너를 사용한다. 

 

AppConfig에 @Configuration을 붙여주고, 스프링 컨테이너가 이 AppConfig를 설정 정보로 사용한다. 메소드에는 @Bean을 붙여주는데, 이걸 붙이면 스프링이 자체적으로 메소드를 모두 호출해 반환된 객체스프링 컨테이너에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체가 스프링 빈이다.

 

필요한 객체가 스프링 빈으로서 스프링 컨테이너에 들어있기 때문에 개발자는 필요한 객체를 스프링 컨테이너에서 찾아 사용하면 된다. 스프링 컨테이너의 메소드인 applicationContext.getBean() 메소드를 사용하여 찾을 수 있다!

 

스프링 컨테이너에 대해 조금 더 자세히 설명하겠다.

 

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

 

위에서 ApplicationContext는 스프링 컨테이너라고 했다. 정확히는 인터페이스이다. 인터페이스를 사용하는 이유는 다형성 때문인데, 사실 스프링 컨테이너는 XML기반으로도 만들 수 있고, 에노테이션 기반의 자바 설정 클래스로도 만들 수 있다.

(현재 XML은 잘 사용하지 않는다)

 

자바 설정 클래스로 만들고 싶다면, 위 코드같은구조체를 사용해주면 된다. 

 

위 코드를 이용해 스프링 컨테이너를 생성하고 나면, 스프링 컨테이너에 스프링 빈을 저장할 수 있게 된다!  

 

 

✅ 스프링 빈

 

스프링 빈의 이름은 아래와 같이 두가지 방법이 있다.

  • 메소드 이름 사용
  • 직접 부여

주의해야 할 점은 빈 이름은 중복되면 안 된다는 것이다. 같은 이름을 부여하면 오류가 생길 수 있다.

 


2. 스프링 빈 조회

 

    @Test
    @DisplayName("애플리케이션 빈 출력하기")
    void findApplicationBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
            if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
                Object bean = ac.getBean(beanDefinitionName);
                System.out.println("bean = " + beanDefinitionName + " object = " + bean);
            }
        }
    }

 

위 코드를 실행하면 모든 빈의 정보를 출력할 수 있다.

  • ac.getBeanDefinitionNames() ->  스프링에 등록된 모든 빈 이름을 조회하는 메소드
  • ac.getBean() -> 빈 이름을 이용해서 빈 객체 조회

스프링 빈은 스프링 자체에서 사용하는 빈이 있고, 내가 등록한 빈이 있다. 이때 내가 등록한 빈과 스프링 자체의 빈을 구분해주는 메소드가 getRole()이다.

  • ROLE_APPLICATION : 내부 작동을 위해 등록한 빈이 아니라 애플리케이션 개발을 위해 등록한 빈 (외부 라이브러리 등)
  • ROLE_INFRASTRUCTURE : 스프링 내부에서 자체적으로 쓰는 빈

 

스프링 빈을 조회하는 방법은 2가지가 있다.

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

타입이 같은 경우 이름까지 넣어 같이 조회한다. 이때 조회 대상 스프링 빈이 없으면 예외가 발생한다.

NoSuchBeanDefinitionException : No bean named 'xxxxx' available

 

 

구체타입으로 조회하는 방법도 있다. 테스트 메소드 (assertThat)의 isInstanceOf() 를 사용하는 것이다.

assertThat(memberService).isInstanceOf(MemberServiceImpl.class);

 

위 코드는 memberService가 memberServiceImpl의 인스턴스면 True가 반환된다. 이런 메소드도 사용할 수 있으나, 구현에 의존하게 되어 유연성이 떨어진다. 그냥 알아만 두자.

 

 

 

✅ 스프링 빈 조회 - 상속 관계

 

 스프링 빈의 상속관계는 부모 타입으로 조회하면 자식 타입도 함께 조회된다는 것이다. 그래서 자바 최상위 객체인 Object 타입으로 조회하면 모든 스프링 빈을 조회할 수 있다. 그럼 스프링 컨테이너도 살펴볼까 ?

 

BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스
  • 스프링 빈을 관리하고 조회하는 역할 담당
  • getBean() 제공

ApplicationContext

  • BeanFactory 기능을 모두 상속받아 제공
  • 상속받는 기능 (빈 관리, 조회) 외에도 수많은 부가기능 제공
    1. 메시지 소스를 활용한 국제화 기능
    2. 환경변수 (각 환경마다 어떤 DB에 연결할지 환경변수와 관련된 정보처리기능을 함)
      • 개발환경 3가지
        1. 로컬개발환경 (내pc에서 개발한 거_
        2. 테스트서버 (개발환경)
        3. 운영환경 (실제 프로덕션에 나감)
        4. +) 스테이징환경
    3. 애플리케이션 이벤트
    4. 리소스  조회

그래서 BeanFactory를 쓸 일이 없다.

 

 


 

다음 게시글에선 싱글톤 컨테이너에 대해 정리해야겠