[Spring Framework - Core] 1. IoC Container / DI / Bean

mrcocoball·2023년 8월 22일

Spring Framework

목록 보기
2/20

해당 포스트는 Spring.io의 공식 문서를 포함한 레퍼런스와 코드를 통해 Spring Framework의 구조 / 기술에 대해 확인해보고자 하는 포스트입니다.

1. Spring IoC Container / DI / Bean

개요

스프링 프레임워크의 핵심 기술 중에서도 가장 중요한 IoC 컨테이너, IoC 컨테이너가 수행하는 DI, 그리고 컨테이너에 의해 관리되는 객체인 빈(Bean)에 대한 내용입니다.

IoC(Invasion of Control, 제어의 역전)은 흔히들 '개발자가 코드 흐름을 제어하는 것이 아닌, 프레임워크가 코드 흐름을 제어하는 것' 이라고 표현을 합니다. 개발자가 작성한 코드를 프레임워크가 사용한다는 것인데요.

스프링 프레임워크에서는 이러한 IoC를 수행하는 컨테이너를 IoC 컨테이너라고 부르며 IoC의 방식으로 DI(Dependency Injection, 의존성 주입)을 사용하고 있습니다.

IoC 컨테이너는 어플리케이션에 필요한 객체인 빈(Bean)들을 생성하고 DI를 통해 의존성을 주입한 뒤 생명 주기를 관리합니다.

컨테이너(Container)

스프링 프레임워크 핵심 기술 중에서도 핵심이며 DI(의존성 주입)을 통해 IoC를 실현하는 컨테이너입니다.
컨테이너가 어플리케이션 구동에 필요한 객체인 빈(Bean)을 생성하고 의존성을 주입하며 생명 주기를 관리합니다.

IoC 컨테이너의 종류로는 크게 BeanFactoryApplicationContext가 있습니다. BeanFactory 인터페이스가 기본적인 IoC 컨테이너이며 이의 하위 타입 인터페이스가 ApplicationContext입니다.

ApplicationContextBeanFactory의 차이점

  • 컨테이너가 기동할 경우 즉시 모든 빈을 로딩함 (즉시 로딩)
  • 통합 라이프사이클 관리가 가능
  • 자동 BeanPostProcessor, BeanFactoryPostProcessor 등록 가능
    (주석 처리, AOP 기능 등 확장 컨테이너 기능이 필요할 경우 반드시 필수)
  • Spring AOP 기능과의 쉬운 통합이 가능
  • 비즈니스 환경에 필요한 다양한 기술을 지원 (메시지 국제화 등)
  • 어플리케이션 이벤트 발행 가능
  • WebApplicationContext 와 같은 애플리케이션 계층 특정 컨텍스트를 제공

Spring Framework 공식 문서에 따르면 ApplicationContextBeanFactory완벽한 상위 집합 (The ApplicationContext is a complete superset of the BeanFactory) 입니다.

빈(Bean)

어플리케이션을 구성하는 객체이며 IoC 컨테이너에 의해 생성 및 의존성 주입되고 생명 주기가 관리됩니다. Bean 간의 종속성은 컨테이너에서 사용하는 구성 메타데이터(configuration metadata)에 반영됩니다.

의존성(Dependency), 의존성 주입(DI, Dependency Injection)

의존성은 객체 간의 의존관계, 종속성을 의미합니다. 또한 DI(의존성 주입)는 객체 생성 시점에서 생성자 파라미터나 팩토리 메서드 생성자 파라미터를 사용하거나 객체 생성 후 팩토리 메서드 설정 옵션 등으로 필요한 종속성(함께 작동하는 다른 객체 등)을 정의하는 프로세스입니다.

본 포스트에서는

공식 문서에서의 순서와는 달리 다음과 같은 흐름으로 내용을 다루고자 합니다.
어플리케이션을 구성하는 객체인 빈 -> 빈 객체 간 종속성을 다루는 DI -> DI를 통해 빈을 관리하는 IoC 컨테이너

2. Bean

개요

빈(Bean)은 어플리케이션을 구성하는 객체이며 IoC 컨테이너에 의해 관리됩니다.
이러한 빈들은 컨테이너에 제공하는 구성 메타데이터(configuration metadata)로 생성됩니다.

컨테이너 자체 내에서 이러한 빈들의 정의는 BeanDefinition 객체로 표시됩니다.
BeanDefinition은 다음과 같은 요소로 구성됩니다.

  • Class : 정의 중인 빈의 실제 구현 클래스
  • Name : 빈의 이름
  • Scope : 빈의 생명 주기
  • Constructor Arguments : 빈의 생성자 인수
  • Properties : 빈의 속성
  • Autowiring Mode : 빈의 Autowiring 모드
  • Lazy initialization Mode : 빈의 지연 초기화 모드
  • Initialization Method : 초기화 메서드
  • Destruction Method : 소멸 메서드

모든 빈에는 하나 이상의 식별자가 있으며 이러한 식별자는 컨테이너 내에서 고유해야 합니다.
기본적으로 식별자는 id나 name 속성을 사용하여 지정할 수 있는데 명시적으로 식별자를 지정하지 않을 경우 컨테이너는 해당 빈에 대해 고유한 이름을 생성합니다.

(빈 명명 규칙에 따르면 빈 이름은 소문자로 시작하여 카멜 케이스로 지어집니다. 예를 들어 빈 클래스 이름이 TestController일 경우 testController가 됩니다)

인스턴스화

빈 정의는 하나 이상의 객체를 생성하기 위한 정의이며 컨테이너는 요청될 때 빈 정의를 확인하고 해당 빈 정의에 의해 캡슐화된 구성 메타데이터를 사용하여 실제 객체를 생성(또는 획득) 합니다.

이 때 객체를 생성하는 방식을 지정할 수 있는데 기본적으로는 컨테이너 자체가 반사적으로 생성자를 호출하여 빈을 생성하는 생성자 접근 방식이 일반적입니다.

  • 생성자를 사용한 인스턴스화 (생성자 접근 방식)
  • 정적 팩토리 메서드를 사용한 인스턴스화 (팩토리 메서드 방식)
  • 인스턴스 팩토리 메서드를 사용한 인스턴스화 (팩토리 빈, 팩토리 메서드 방식)

범위(Scope)

빈 정의 시 생성된 객체의 생명 주기의 범위를 제어할 수 있습니다. 스프링 프레임워크는 총 6개의 범위를 지원하며 그 중 4개는 웹 인식 ApplicationContext에서만 사용이 가능합니다. 또한 사용자 지정 범위를 만들 수 있습니다.

  • singleton
    기본값이며 각 IoC 컨테이너에 대한 단일 객체 인스턴스에 단일 빈 정의 범위를 지정.
    컨테이너 당 및 빈 당 한 개의 인스턴스만 생성되며 상태가 없는 빈일 경우 싱글톤을 사용해야 함
  • prototype
    단일 빈 정의를 여러 객체 인스턴스로 범위를 지정.
    특정 빈에 대한 요청이 있을 때마다 새로운 빈 인스턴스를 생성하며 상태가 있는 빈에는 프로토타입을 사용
  • request
    단일 HTTP 요청의 라이프사이클에 대한 단일 빈 정의의 범위를 지정.
    각 HTTP 요청마다 단일 빈 정의를 통해 생성된 빈 객체가 있음. 웹 인식 ApplicationContext에서만 유효
  • session
    단일 빈 정의를 HTTP 세션의 생명 주기로 범위를 지정. 웹 인식 ApplicationContext에서만 유효
  • application
    ServletContext의 생명 주기에 대한 단일 빈 정의의 범위를 지정. 웹 인식 ApplicationContext에서만 유효
  • websocket
    웹 소켓의 생명 주기에 대한 단일 빈 정의의 범위를 지정. 웹 인식 ApplicationContext에서만 유효
  • 사용자 지정 범위
    사용자가 직접 범위를 정의하거나 singleton, prototype 범위를 제외한 나머지 범위를 재정의할 수 있음.
    Scope 인터페이스를 구현하여 사용하며 메서드에 대한 내용은 다음과 같음.
public abstract class CustomScope implements Scope {

	// 기본 범위에서 객체를 반환
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        return null;
    }

	// 기본 범위에서 객체를 제거
    @Override
    public Object remove(String name) {
        return null;
    }

	// 범위가 소멸되거나 범위의 지정된 객체가 소멸될 때 범위가 호출해야 하는 콜백
    @Override
    public void registerDestructionCallback(String name, Runnable callback) {

    }

	// 범위에 대한 대화 식별자를 가져옴
    @Override
    public String getConversationId() {
        return null;
    }
    
    // 주어진 키에 대한 컨텍스트 객체를 확인 (있는 경우)
    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }
}

특성 사용자 정의

빈 수명 주기의 컨테이너 관리와 상호 작용하기 위한 InitializingBeanDisposableBean 인터페이스를 구현할 수 있습니다. 각각 컨테이너는 빈의 초기화 / 파괴 시 빈이 특정 조치를 수행하도록 afterPropertiesSet()destory() 메서드를 지정합니다.

다만 이 경우 어플리케이션이 스프링 프레임워크에 불필요하게 종속되기 때문에 공식 문서에서는 이보다는 JSR 표준인 @PostConstruct, @PreDestroy 어노테이션을 사용하는 것을 권장하고 있습니다.

이밖에도 스프링 프레임워크가 기본적으로 제공하지 않는 사용자 지정 기능이나 기타 수명 주기 동작이 필요할 경우에는 후술할 BeanPostProcessor 를 통해 직접 구현할 수 있습니다.

초기화 및 소멸 콜백 외에도 스프링 프레임워크 관리 객체는 Lifecycle 인터페이스를 구현하여 해당 객체가 컨테이너 자체 수명 주기에 따라 시작 및 종료 프로세스에 참여할 수 있습니다.

3. Dependency Injection

개요

의존성 주입 원칙을 사용하면 코드가 더 깔끔해지고 객체에 종속성이 제공될 때 분리가 더 효과적입니다.
객체는 종속성을 조회하지 않으며 종속성의 위치나 클래스를 알지 못합니다.

이 덕분에 종속성이 인터페이스나 추상 기본 클래스에 있을 때 클래스를 테스트하기가 쉬워지며 이를 통해 Stub 또는 모의 구현을 단위 테스트에 사용할 수 있다고 합니다.

DI는 생성자 기반 종속성 주입Setter 기반 종속성 주입의 두 가지 주요 변형이 있습니다.

생성자 기반 종속성 주입

각각 종속성을 나타내는 여러 인수를 사용하여 생성자를 호출하는 컨테이너에 의해 수행하는 방식입니다.

public class TestMovieController {

	// TestMovieService와의 의존성이 있음
    private final TestMovieService service;
    
    // TestMovieController의 생성자이며 스프링 컨테이너가 TestMovieService를 주입할 수 있음
    public TestMovieController(TestMovieService service) {
    	this.service = service;
    }

}

Setter 기반 종속성 주입

인수가 없는 생성자(@NoArgsConstructor) 또는 인수가 없는 정적 팩토리 메서드를 호출하여 빈을 인스턴스화한 후 빈에서 세터 메서드를 호출하는 컨테이너에 의해 수행됩니다.

public class TestMovieController {

	// TestMovieService와의 의존성이 있음
    private final TestMovieService service;
    
    // service의 세터 메서드이며 스프링 컨테이너가 TestMovieService를 주입할 수 있음
    public void setService(TestMovieService service) {
    	this.service = service;
    }

}

생성자 기반 vs Setter 기반

생성자 기반, Setter 기반 모두 혼합 사용이 가능하며 공식 문서에는 다음과 같은 견해를 밝히고 있습니다.

  • 필수 종속성에 대해서는 생성자 기반을 사용 / 선택적 종속성에 대해서는 세터 메서드 또는 구성 메서드를 사용
  • 일반적으로 스프링 팀은 다음과 같은 이유로 생성자 기반 방식을 옹호함
    • 애플리케이션 구성 요소를 불변 객체로 구현하고 필수 종속성이 null이 아님.
    • 생성자 주입 구성 요소는 항상 완전히 초기화된 상태로 클라이언트(호출) 코드에 반환됨.
    • 다만 생성자에 파라미터가 많을 경우 해당 빈이 너무 많은 책임을 가지고 있다는 것이므로 적절히 분리가 필요
    • 순환 종속성 문제(A가 B를, B가 A를 필요로 하는 경우 등) 가 발생할 수 있으므로 주의
  • Setter 기반은 기본적으로 클래스 내에서 합리적인 기본값을 할당할 수 있는 선택적 종속성에만 사용해야 함 -> 그렇지 않을 경우 코드가 종속성을 사용하는 모든 곳에서 null 여부를 검사해야 함
  • Setter 기반의 이점은 Setter 메서드가 해당 클래스의 객체를 나중에 재구성하거나 다시 주입할 수 있도록 만드는 것

가장 중요한 것은 특정 클래스에 가장 적합한 DI 스타일을 사용하는 것이라고 합니다.
DI 스타일마다 트레이드 오프가 있으니 공식 문서의 견해를 참고하며 사용하는 것이 좋을 것 같습니다.

지연 초기화

getBean() 메서드가 동작해야 빈을 로딩(지연 로딩)하는 BeanFactory와 달리 ApplicationContext 는 초기화 시 모든 빈을 생성하여 로딩(즉시 로딩)합니다.

다만 이러한 동작으로 인해 오류가 발생하는 경우(앞에서 이야기한 순환 종속성 문제 등) 초기화 전략을 지연 초기화로 설정할 수 있습니다. default-lazy-init=true

Autowiring Collaborators

XML 기반 구성 메타데이터에서 서로 협업하는 빈 간의 관계를 Autowiring을 통해 자동으로 연결할 수 있습니다.
다만 한계와 단점이 명확하여 현재는 거의 사용이 되지 않는 것으로 보입니다.

  • 명시적 연결보다 덜 정확한 연결 -> 빈 객체 간의 관계가 명시적으로 문서화되지 않음
  • 컨테이너에서 문서를 생성할 수 있는 도구에는 연결 정보가 제공되지 않음
  • 컨테이너 내 여러 빈 정의는 autowired될 세터 메서드 또는 생성자 인수에 의해 지정된 유형과 일치할 수 있음 -> 단일 값을 예상하는 종속성의 경우 모호해질 수 있으며 고유한 빈 정의를 사용할 수 없다면 예외가 발생

메서드 주입

대부분의 경우 어플리케이션을 구성하는 빈은 싱글톤이지만 간혹 협업 관계가 있는 두 빈의 생명 주기가 다른 경우 (빈 A가 싱글톤인데 빈 B가 프로토타입인 경우) 문제가 생길 수 있습니다.

이럴 때 메서드 주입을 통해 빈이 다른 빈을 요청할 수 있도록 컨테이너를 호출한 후 필요한 빈을 인식할 수 있습니다.

4. IoC Container

개요

인터페이스 ApplicationContext 는 IoC 컨테이너이며 빈의 인스턴스화와 구성 및 조립을 담당합니다. 이 때 구성 메타데이터(configuration metadata)를 읽어 인스턴스화, 구성 및 조합을 할 객체에 대한 지침을 얻습니다. 구성 메타데이터는 XML, Java 어노테이션 또는 java 코드로 표시됩니다.

ApplicationContext 는 여러 구현체가 있는데 대표적으로 다음과 같습니다.

  • ClassPathXmlApplicationContext
  • FileSystemXmlApplicationContext
  • AnnotationConfigApplicationContext
  • WebApplicationContext
  • 등...

구성 메타데이터(configuration metadata)

위에서 소개한 대로 IoC 컨테이너는 구성 메타데이터를 통해 어떤 객체를 인스턴스화 하고 구성, 조합하는지에 대해 확인합니다. 구성 메타데이터를 사용하는 방법은 크게 다음과 같습니다.

  • XML 기반 구성
    전통적이고 간단하고 직관적인 XML 형식으로 구성을 제공, <beans/> 요소 내의 <bean/> 으로 작성
  • 어노테이션 기반 구성
    스프링 또는 JSR 표준 어노테이션을 사용 (예시 : @Autowired, @Inject, @Named)
  • Java 기반 구성
    XML이 아닌 java 코드를 사용하여 애플리케이션 클래스 외부에 있는 빈을 정의. 많은 개발자들이 사용하는 방식이며 @Configuration, @Bean, @Import, @DependsOn 등을 사용

컨테이너 인스턴스화 및 사용

컨테이너를 특정 구현체로 인스턴스화한 후 사용할 수 있습니다. 예를 들어 ClassPathXmlApplicationContext 로 인스턴스화할 경우 생성자의 파라미터에 위치 경로를 기입하여 해당 위치에 있는 컨테이너의 구성 메타데이터를 가져올 수 있습니다. 이 때 사용되는 위치 경로는 스프링 프레임워크의 Resource 추상화와 관련되어 있습니다.

  • ClassPathXmlApplicationContext (XML 기반 구성) 생성자 일부
  • AnnotationConfigApplicationContext (어노테이션, Java 기반 구성) 생성자 일부
// services.xml, daos.xml의 구성 메타데이터 확인, 빈 생성
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml")

// 정의된 빈 객체를 검색
TestService service = context.getBean("testService", TestService.class);

// 정의된 빈 객체를 사용
List<String> userList = service.getUserList();

getBean() 메서드를 통해 구성 메타데이터에 정의된 빈 객체들을 검색할 수 있으나 공식 문서에 따르면 실질적으로 개발자가 해당 메서드를 어플리케이션 코드에서 사용하는 일은 없어야 한다고 합니다. (어플리케이션 코드가 스프링 API에 의존하지 않도록 해야 하므로)

어노테이션 기반 컨테이너 구성

XML 기반 구성 대신 관련 클래스, 메서드 또는 필드 선언에 대한 주석을 사용하여 구성 요소 클래스 자체로 구성을 진행할 수 있습니다. 이 때 @Autowired 를 비롯한 어노테이션을 통해 구성 메타데이터를 구성합니다.

어노테이션 기반으로 구성 메타데이터를 구성할 경우 후술할 PostProcessor들이 암시적으로 사용됩니다.

  • ConfigurationClassPostProcessor
  • AutowiredAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor
  • PersistenceAnnotationBeanPostProcessor
  • EventListenerMethodProcessor

어노테이션 기반 구성과 관련된 어노테이션은 다음과 같습니다.

  • @Autowired
    생성자, Setter, 메서드, 필드에 부착하며 구성 메타데이터에서 빈들을 검색한 후 적절한 빈을 주입.
    XML 기반 구성의 Autowiring Collaborator가 제공하는 기능보다 더 세밀한 제어가 가능
  • @Order
    빈이 주입될 때 우선 순위를 정할 수 있음. 단, 싱글톤 시작 순서에는 영향을 미치지 않음
  • @Primary
    여러 빈이 단일 값 종속성에 자동 연결될 수 있을 경우 특정 빈에 부착하여 그 빈에 우선 순위를 부여함
  • @Qualifier
    여러 빈 중 단일 값 종속성에 한정자 값과 특정 인수를 연결지어 유형이 일치하는 빈을 선택하도록 함
  • @Resource
    필드나 Setter 메서드에 부착이 가능하며 기본적으로 @Autowired와 유사
  • @Value
    외부화된 속성을 주입할 때 사용
  • @PostConstruct, @PreDestroy
    위에서 소개한 빈의 초기화 / 파괴 시점에 콜백이 작동될 수 있도록 하는 어노테이션
  • JSR 330 표준 어노테이션들
    • @Inject, @Named

어노테이션 기반 구성의 주의할 점은 XML 기반 구성이 이뤄지기 전에 구성이 된다는 것, 그리고 XML 파일(ApplicationContext)에서 <context:annotation-config/> 를 입력한 경우, 해당 XML 파일에서 정의된 빈들만 탐색하게 된다는 것입니다.

클래스 경로 스캔 및 컴포넌트 관리

XML 기반 구성이 아닌 클래스 경로를 스캔하여 후보 구성 요소(Candidate Components)를 감지하는 옵션이 클래스 경로 스캔입니다. 여기서 후보 구성 요소란 필터 기준과 일치하고 해당 빈 정의가 컨테이너에 등록된 클래스입니다.

클래스 경로 스캔을 사용하기 위해선 @Component와 같은 어노테이션이나 AspectJ 표현식, 또는 사용자 정의 필터 기준을 사용하여야 하며 이를 통해 컨테이너에 등록된 빈 정의가 있는 클래스를 선택할 수 있습니다.

@Component는 스프링 프레임워크가 관리하는 컴포넌트에 대한 일반적인 스테레오 타입이며 메타 어노테이션입니다.
@Component 를 활용해 보다 구체적인 사용 사례에 대해 전문화한 어노테이션들의 대표적인 사례가 @Controller, @Service, @Repository 입니다.

스프링은 이러한 스테레오 타입 클래스들을 자동으로 감지하여 해당 클래스들에 대한 BeanDefinition 인스턴스를 ApplicationContext에 등록합니다. 이렇게 BeanDefinition이 등록된 클래스들을 자동으로 감지하고 빈으로 등록하려면 @Configuration 가 부착된 클래스에 @ComponentScan을 부착해야 합니다.

@Repository
public class TestRepository {
	...
}

@Configuration
@ComponentScan(basePackages = "org.example)
public class AppConfig {

}

또는, @Component 어노테이션이 부착된 클래스 내부에 @Bean을 부착시킨 메서드에서 빈을 반환하는 것으로 빈 정의 메타데이터를 컨테이너에 제공할 수도 있습니다.

@Component
public class FactoryComponent {

	@Bean
    public TestBean testBean() {
    	return new TestBean();
    }

}

Java 기반 컨테이너 구성

Java 기반 컨테이너 구성은 java 코드를 사용하여 컨테이너를 구성하는 것으로 핵심적인 요소는 @Bean@Configuration 입니다. @Bean@Configuration에 대해 간단하게 설명하자면 다음과 같습니다.

  • @Bean
    메서드에 부착하며 해당 메서드가 컨테이너에서 관리할 새 객체를 인스턴스화, 구성 및 초기화함을 나타냄
    XML 기반의 <bean/> 와 같은 기능
  • @Configuration
    클래스에 부착하며 해당 클래스가 빈 정의의 소스임을 나타냄
    같은 클래스 내에 존재하는 @Bean이 부착된 메서드를 호출하여 빈 간 종속성을 정의할 수 있음

공식 문서에 따르면 @Bean@Configuration 이 선언된 클래스 내에 있는 메소드에 선언될 경우에는 'full' 모드, 아닌 경우(이를테면 @Component) 'lite' 모드로 동작한다고 하는데, lite 모드에서의 @Bean 은 빈 간 종속성을 선언할 수 없고 다른 @Bean 메서드를 호출해서는 안된다고 합니다. 이러한 연유로 공식 문서에서는 가급적 @Configuration 내에 @Bean을 선언하는 것을 권장하고 있습니다.

@Configuration
public class AppConfig

	@Bean
    public BeanOne beanOne() {
    	return new BeanOne(beanTwo());
    }
    
    @Bean
    public BeanTwo beanTwo() {
    	return new BeanTwo();
    }

컨테이너 확장

개발자들이 ApplicationContext 의 구현 클래스를 확장하고 싶다면 별도의 하위 클래스를 만들 필요 없이 특수 통합 인터페이스의 구현체를 플러그인하여 확장할 수 있습니다. 대표적인 특수 통합 인터페이스는 다음과 같습니다.

  • BeanPostProcessor
    스프링 컨테이너가 빈 인스턴스화, 구성 및 초기화를 마친 이후 작동할 사용자 정의 로직을 구현할 때 사용.
    빈 인스턴스화한 시점에서 해당 인터페이스의 인스턴스가 동작하며 컨테이너 당 한 개의 BeanPostProcessor 인스턴스가 존재함. BeanPostProcessor를 활용한 대표적인 사례가 Spring AOP
  • BeanFactoryPostProcessor
    BeanPostProcessor와 기능은 유사하나 차이점은 Bean 구성 메타데이터에서 작동. 즉, 스프링 컨테이너가 구성 메타데이터를 읽고 BeanFactoryPostProcessor 인스턴스 이외의 빈을 인스턴스화하기 전에 작동함
  • FactoryBean
    스프링 컨테이너의 인스턴스화 로직을 사용자 지정해야 할 경우 구현하는 인터페이스
    팩토리가 생성하는 객체의 인스턴스를 반환하거나, 싱글톤 반환 여부를 체크하거나 메서드에서 반환된 객체 유형을 반환하거나 유형을 알 수 없는 경우 null을 반환할 수 있음

환경 추상화

어플리케이션 환경과 관련된 프로필이나 속성을 추상화하는 Environment 인터페이스를 제공합니다.
@Profile 어노테이션을 통해 컨테이너 내 빈이 동작하기 위해 활성화되어야 할 프로필을 지정할 수 있습니다.
속성은 각종 속성 파일, JVM 속성, 시스템 환경 변수 등 다양한 소스에서 발생할 수 있는 속성을 의미하며 PropertySource, @PropertySource 등을 사용하여 검색을 할 수 있습니다.

LoadTimeWeaver

@EnableLoadTimeWeaving, @Configuration 을 통해 클래스가 JVM에 로드될 때 동적으로 변형시키기 위해 사용합니다.

5. 정리

IoC 컨테이너는 어플리케이션을 구성하는 객체인 빈을 생성하고 DI를 통해 의존성을 주입하고 관리하는 역할을 합니다. BeanFactory와 ApplicationContext가 있으며 ApplicationContext가 보다 많은 기능을 가지고 있어 대부분 ApplicationContext를 활용한 구현체들을 사용하게 됩니다.

컨테이너는 빈 정의(BeanDefinition)과 해당 빈 정의에 의해 캡슐화된 구성 메타데이터를 활용하여 빈을 인스턴스화합니다.

이를 위해서 빈들은 컨테이너 내 구성 메타데이터(configuration metadata)에 등록이 되어야 하는데 이런 구성 메타데이터를 만드는 방법은 크게 XML 기반 구성, 어노테이션 기반 구성, Java 기반 구성이 있으며 각자 다른 방식으로 빈들을 구성 메타데이터에 등록합니다.

DI는 스프링 프레임워크에서 IoC를 실현하기 위한 방법이며 크게 생성자 기반 방식과 Setter 기반 방식이 있으며 공식 문서에서는 생성자 기반 방식을 권장하고 있습니다.

빈의 생명 주기는 총 6가지가 있으며 기본값은 싱글톤(singleton) 입니다.
만약 서로 종속성을 가진 두 빈의 생명 주기가 다를 경우 지연 초기화를 이용하거나 메서드 주입 방식을 통해 종속성을 주입하여야 합니다.

Appendix. 출처

https://docs.spring.io/spring-framework/reference/core/beans.html
https://www.baeldung.com/spring-beanfactory-vs-applicationcontext

profile
Backend Developer

0개의 댓글