본문 바로가기
Framework/Spring

[Spring Boot] Container

by 코딩하는 랄로 2023. 11. 8.
728x90

스프링 컨테이너

스프링 컨테이너는 스프링 프레임워크, 스프링 부트의 핵심 컴포넌트이다. 스프링에서는 외부에서 자바 객체의 생명 주기를 관리하며, 생성된 자바 객체들에게 추가적인 기능을 제공하는데, 이 역할을 담당하는 '외부'가 바로 컨테이너인 것이다.

 

컨테이너가 담고 있는 자바 객체를 스프링에서는 빈(Bean) 객체라고 부르는데, 컨테이너는 빈의 생성,관리, 제거 등 생명주기를 관리하며, 생성된 빈에게 의존성 주입 등 추가적인 기능을 제공하는 것이다.

 

 

 

스프링 컨테이너의 종류

스프링 컨테이너는 내부에 있는 자바 객체를 이용하여 빈 객체를 생성하기도 하고, 관계를 설정하기도 하는 등 마치 Bean 객체를 하나의 부품으로 사용한다. 워낙 다양한 기능을 가지고 있다보니, 여러가지 이름으로 불리기도 하는데 그 중 대표적인 것이 context, factory, IoC container 등이 있다.

 

여러가지 이름으로 불리지만 스프링 컨테이너의 종류는 두가지로 나뉘는데, 하나는 BeanFactory이고, 나머지 하나는 BeanFactory를 상속받는 ApplicationContext이다.

 

BeanFactory 는 빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트이고, BeanFactory 를 좀 더 확장한 것이 ApplicationContext 이다. ApplicationContext 는 IoC 방식을 따라 만들어진 일종의 BeanFactory로 둘 다 동일한 개념이라 생각하면 된다. 주로 사용되는 스프링 컨테이너는 ApplicationContext 이다.

 

 

BeanFactory

BeanFactory는 스프링 컨테이너의 최상위 인터페이스로 빈을 등록, 생성, 조회 등 빈을 관리하는 역할은 한다. 또한 getBean() 메서드를 통해 빈을 객체화할 수 있다.

 

빈을 등록을 하는 방법으로는 @Bean 어노테이션을 붙임으로 해당 메소드의 이름을 사용하는 빈 객체가 등록이 된다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//클래스 이름앞에 반드시 어노테이션 명시 필요
//@Configuration --> 이 클래스는 '스프링 설정'에 사용되는 클래스 입니다.
//결국 IOC 컨테이너에 생성되는 bean 들을 기술하는 클래스 --> @Bean 사용

@Configuration
public class BeanExample {
    public BeanExample() {
        System.out.println("BeanExample() 생성");
    }

    // 리턴타입의 bean 객체 생성, 기본적으로 bean 의 이름은 메소드 이름으로 설정
    @Bean
    public Test test() {
        System.out.println("test() 호출");
        return new Test();
    }
}

class Test {
    public Test() {};
}

 

 

ApplicationContext

ApplicationContext는 BeanFactory 인터페이스의 빈 객체를 관리하고 검색하는 기능을 상속 받아 제공하고, 그 이외의 부가 기능 또한 제공하고 있다. (ApplicationContext는 BeanFactory의 확장 버전!!)

 

부가 기능으로는 아래와 같은 기능들을 제공하고 있다.

기능 설명
MessageSource 메세지 다국화를 위한 인터페이스
EnvironmentCapable 개발, 운영, 환경 변수 등으로 나누어 처리하고, 애플리케이션 구동 시 필요한 정보들을 관리하기 위한 인터페이스
ApplicationEventPublisher 이벤트 관련 기능을 제공하는 인터페이스
ResourceLoader 파일, 클래스 패스, 외부 등 리소스를 편리하게 조회

 

위의 기능들은, 스프링 부트를 공부하면서 하나 하나 알아 볼 것이다.

 

 

 

스프링 컨테이너의 특징

스프링 컨테이너의 특징들에는 무엇이 있으며, 해당 특징을 통해 얻을 수 있는 이점에 대해서 알아보겠다.

  • 컨테이너는 개발자가 정의한 빈을 객체로 만들어 관리하고 개발자가 필요로 할 때 제공
  • 의존성 주입을 통해 유지 보수성을 높이고 손쉽게 애플리케이션의 컴포넌트를 관리
  • 서로 다른 빈을 연결하여 애플리케이션 빈을 연결하는 역할

이러한 특징으로, 개발자는 모듈간에 의존 및 결합으로 인해 발생하는 문제를 최소화할 수 있고, 컨테이너가 알아서 메소드의 빈 객체를 통해 객체를 주입해주기 때문에, 객체를 생성하고 호출하는 등의 번거로운 과정에서 자유로워질 수 있다. 

 

즉, 스프링 컨테이너를 사용함으로써, 객체 간의 의존성을 낮추고, 높은 캡슐화가 가능해진 것이다. 또한 스프링 컨테이너를 사용함으로 구현 클래스에 있는 의존성이 제거되고, 인터페이스에만 의존하도록 설계할 수 있게 되면서 유지보수성이 월등히 높아졌다.

 

 

 

스프링 컨테이너 생성 과정

기본적으로 스프링 컨테이너는 Configuration Metadata를 사용한다. 또한, 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용하여 스프링 빈을 등록한다. 이 때에 설정 클래스를 지정할 수 있는 어노테이션이 위의 예제 코드에서 사용한 @Configuration이다.

 

스프링 컨테이너를 만드는 다양한 방법은 ApplicationContext 인터페이스의 구현체이다. AppConfig.class 등의 구성 정보를 지정하여 스프링 컨테이너를 생성할 수 있다. 애플리케이션 클래스는 구성 메타데이터와 결합되어 ApplicationContext를 생성하고 초기화된다. 이후 실행 가능한 시스템 또는 애플리케이션을 갖게 된다.

 

만약, 스프링 빈 조회에서 상속관계가 있을 시에는 부모 타입으로 조회하면 자식 타입도 함께 조회된다. 즉, Object 타입으로 조회하게 되면 모든 스프링 빈을 조회할 수 있다.

 

 

 

ApplicationContext 컨테이너 정보 확인

일반적으로, 스프링 부트에서는 BeanFactory보다 ApplicationContext를 컨테이너로 사용한다. (어차피 BeanFactory의 기능을 물려받았기 때문!!) 그렇기 때문에, 현재 컨테이너가 어떠한 빈 객체를 가지고 있는지 등 여러 정보들을 어떻게 확인하는지 알아보자.

@SpringBootApplication
public class Main implements CommandLineRunner {
    // ApplicationContext 객체를 담을 변수 선언
    ApplicationContext ctx;

    // 자동주입 (setter injection)
    // => ApplicationContext 객체를 ctx에 넣어주기
    @Autowired 
    public void setCtx(ApplicationContext ctx) {
        this.ctx = ctx;
    }

    public Main() {
        System.out.println("Main 객체 생성");
    }

    public static void main(String[] args) {
        
        System.out.println("Main 시작");

        SpringApplication.run(Main.class, args);

        System.out.println("Main  종료");
    }

    @Override
    public void run(String... args) throws Exception {
        // 컨테이너 안에 생성된 bean 정보 조회
        System.out.println("생성된 빈의 개수: " + ctx.getBeanDefinitionCount());

        // 모든 bean 에는 name(id) 이 부여된다.
        for(var name : ctx.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

 

위의 코드에서, ApplicationContext 객체를 생성하기 위한 과정은 지금은 깊게 알 필요가 없다. 지금은 생성한 ApplicationContext 객체를 통해 생성된 bean 정보를 조회하고 현재 컨테이너에 대한 정보를 알 수 있다는 정도만 알고 넘어가자!!

728x90