도림.로그

Tags

Series

About

[Spring 공부] Spring 핵심 원리 - 3

2022. 02. 25.

Spring Study

▶ Expand post list

    Spring에 대해 처음 공부하는 사람이 정리를 목적으로 작성한 글입니다. 오개념 등 잘못된 부분이 있을 경우 댓글로 가감없이 지적해주세요! 확인하는 대로 정확한 정보를 기반해 빠르게 수정할 수 있도록 하겠습니다.

    개요

    이번 Spring Boot 스터디는 배달의 민족의 김영한님께서 인프런에 올려주시는 자바 스프링 완전 정복 시리즈를 기반으로 진행한다. 그 시리즈의 가장 첫 강의인 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술을 끝내고, 다음 강의인 스프링 핵심 원리 - 기본편을 정리해보려 한다.

    이번 포스트에서는 Spring 컨테이너와 Spring 빈에 대한 것을 간단히 정리해보도록 하겠다.

    Spring 컨테이너

    ApplicationContext

    스프링에서는 ApplicationContext 라는 것을 Spring 컨테이너라고 한다. 이외에도 BeanFactory 가 있긴 하지만, 이에 대해서는 후술하도록 하겠다.

    이전 포스트를 보면, 우리는 DriveConfig 를 사용해서 직접 객체를 생성(new)하고 관리했지만, 이제부터는 Spring 컨테이너를 사용해서 관리할 것이다. Spring 컨테이너는 @Configuration 어노테이션이 붙은 클래스를 설정 정보로 사용하는데, 이 클래스에서 @Bean 이 붙은 메서드를 모두 호출해서 해당 메서드에서 반환된 객체를 Spring 컨테이너에 등록한다. 이렇게 Spring 컨테이너에 등록된 객체를 Spring 빈이라고 한다. 이렇게 등록된 Spring 빈에는 각자 이름이 있는데, 기본적으로 @Bean 이 붙은 메서드 명을 빈 이름으로 사용한다.

    직접 Config 파일을 작성하여 DI 컨테이너로 사용할 때에는 테스트 코드를 작성할 때, 우리가 Config 를 활용하여 직접 객체를 빼다 썼어야 했는데, Spring 컨테이너를 사용하면 Spring 컨테이너를 통해서 필요한 Spring 빈(객체)를 찾아야 한다. 이런 상황에서는 applicationContext.getBean() 메서드를 활용하여 필요한 빈을 찾아올 수 있다.

    즉, 기존에는 개발자가 직접 자바 코드를 작성해서 필요한 객체를 찾아와야 했지만, 이제는 스프링 프레임워크에 관리의 권한을 위임하고, 필요한 객체를 스프링으로부터 요청하여 사용하는 형태로 바뀌었다. 얼핏 보기에는 이런 변화는 코드를 조금 더 복잡하게 만드는 느낌을 주기도 한다. 하지만 스프링이 빈을 관리해주면 성능적인 부분이나, 싱글톤으로의 관리 등 수많은 부분에 장점이 있기 때문에 Spring 컨테이너를 도입하는 것이 큰 이득이 된다.

    컨테이너 생성 과정

    ApplicationContext 를 생성할 때에는 기본적으로 구성 정보를 전달해 주어야 하는데, 이 구성 정보의 형태에는 자바 코드와 XML 파일 두 가지 형태가 있다. 최근에는 XML 방식을 잘 쓰지 않기도 하고, 또 XML 방식의 코드가 너무 알아보기 어려울 정도로 복잡한 것은 아니기 때문에 일단 자바 코드를 통해서 설정하는 경우를 상정하여 글을 써보도록 하겠다.

    예를 들어, 설정 정보의 이름은 AppConfig 이고, 내부의 내용은 다음과 같다고 가정하자.

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

    강의에서 다룬 간단한 주문 관리 예제의 AppConfig 이다.

    그리고 이것을 활용하여 다음과 같이 Spring 컨테이너를 생성한다고 가정하자.

    public class SampleApplication {
        ApplicationContext ac = new AnnotationConfigApplitacionContext(AppConfig.class);
    }

    그러면 다음의 과정을 거쳐서 Spring 컨테이너가 생성된다.

    1. Spring 컨테이너 생성

    일단, Spring 컨테이너를 생성한다. Spring 컨테이너 내부에는 Spring 빈 저장소가 있는데, 마치 Map 의 형태로 빈 이름과 빈 객체를 매핑되어 있는 형태이다.

    spring_container_01.png

    2. Spring 빈 등록

    이제, 구성 정보를 활용하여 이 빈 저장소를 채우게 된다.

    spring_container_02.png

    이 때, 참고로 빈 이름은 기본적으로 메서드의 이름이 되지만, @Bean(name="mainMemberService") 와 같이 직접 설정해줄 수도 있다. 이 때 주의해줘야 할 점은, 빈의 이름은 항상 다른 이름을 부여해야 한다는 것이다. 빈의 이름이 겹치면 기존에 등록된 빈을 덮어써버리거나, 아니면 최근 Spring Boot의 경우 아예 빌드가 되지 않는다.

    3. Spring 빈 의존 관계 설정

    Spring 빈 등록이 끝나면, 가령 아래 그림처럼 Spring 컨테이너에 빈들이 등록되어 있을 것이다.

    spring_container_03.png

    여기서 멈추지 않고, Spring 빈 사이의 의존 관계를 구성 정보를 통해 확인하고 필요한 의존 관계를 주입해준다.

    spring_container_04.png

    단순히 자바 코드를 호출하는 것 같지만, 사실 조금 더 복잡한 방식을 통해서 이뤄진다. 이는 후에 싱글톤 컨테이너를 학습하면서 정리할 생각이다.

    엄밀하게는

    사실 엄밀하게는 이렇게 단계별로 딱 딱 작업이 이루어지는 것이 아니다. 자바 코드를 통해서 구성 정보를 설정하면, 생성자를 호출하면서 의존 관계도 바로바로 설정하게 된다. 하지만 개념적인 이해를 돕기 위해 강의에서는 위와 같이 단계적으로 설명하신 것 같다. 추후 의존 관계 자동 설정 파트에서 이 내용을 다시 다루면서 조금 더 상세하게 정리한다.

    BeanFactory, ApplicationContext

    위에서 Spring 컨테이너에는 ApplicationContext 뿐 아니라, BeanFactory 도 있다고 했다. 이 둘의 관계에 대해서 알아보자.

    사실 별다른 부분이 있는 것은 아니고, ApplicationContextBeanFactory 를 상속하여 기능을 더 확장한 인터페이스이다. 간단히 정리해보면 다음과 같다.

    BeanFactory

    • Spring 컨테이너의 최상위 인터페이스
    • Spring 빈을 조회하고 관리하는 기본적인 기능은 모두 여기 명시되어 있음
    • 예를 들어 getBean() 제공

    ApplicationContext

    • BeanFactory 를 상속받기 때문에 기본적인 BeanFactory 의 기능은 모두 제공
    • 애플리케이션을 개발하기 위한 빈 관리 이외의 수많은 부가 기능들을 제공

    ApplicationContext가 제공하는 부가 기능

    • 메시지 소스를 활용한 국제화 : 사용자 별로 다른 언어를 지원해야 할 때 필요한 기능
    • 환경 변수 : 로컬, 개발, 운영을 구분하여 처리할 때 필요한 기능
    • 애플리케이션 이벤트 : 이벤트 발생, 구독 모델을 편리하게 처리할 수 있는 기능
    • 편리한 리소스 조회 : 파일, 클래스패스 등의 리소스를 편리하게 조회할 수 있는 기능

    따라서

    메모리가 극한으로 부족한 서버(??? : RAM은 640KB면 충분합니다.)가 아니라면 그냥 ApplicationContext 를 사용하면 된다. 굳이 제공되는 수많은 부가 기능들을 마다할 이유가 없다.

    다음은

    이상, Spring 컨테이너와 Spring 빈에 대한 내용들에서 중요하다고 느낀 부분들을 간략히 정리해 보았다. Spring 컨테이너와 Spring 빈에 대해 굉장히 깊고, 많은 내용들이 있기 때문에 해당 내용들은 어느정도의 개괄, 개요에 해당하는 내용이라고 생각한다. 이번 강의가 다 끝날 때 즈음까지 이 내용을 뼈로 삼아 더 많은 살을 붙여나가지 않을까 예상된다.

    다음 포스트에서는 싱글톤 컨테이너에 대한 내용을 다뤄보도록 하겠다.

    끝.

    #java#spring#inflearn#DI#container#spring bean

    © 2024, Built with Gatsby