2023. 4. 25. 12:20ㆍSpring Framework/Spring IoC
Introduction to the Spring IoC Container and Beans
이 장에서는 Inversion of Control (IoC) 원칙의 Spring Framework 구현에 대해 다룹니다.
의존성 주입 (Dependency Injection, DI)은 IoC의 특수한 형태로, 객체가 자신이 작업하는 다른 객체들을 컨스트럭터 아규먼트, 팩토리 메서드의 아규먼트, 또는 객체 인스턴스가 생성되거나 팩토리 메서드에서 리턴된 후에 설정되는 속성을 통해서만 정의하는 방법입니다. IoC 컨테이너는 빈을 생성할 때 이러한 의존성을 주입합니다. 이 과정은 본질적으로 bean 자체가 클래스의 직접 생성 또는 서비스 로케이터 패턴과 같은 메커니즘을 사용하여 자신의 의존성을 인스턴스화하거나 위치를 제어하는 것의 반대(따라서 Inversion of Control이라는 이름)입니다.
[참고]
org.springframework.beans 및 org.springframework.context 패키지는 Spring Framework의 IoC 컨테이너의 기반이 됩니다. BeanFactory 인터페이스는 모든 타입의 객체를 관리할 수 있는 고급 구성 메커니즘을 제공합니다. ApplicationContext는 BeanFactory의 하위 인터페이스입니다. ApplicationContext는 다음을 추가합니다:
- Spring의 AOP 기능과의 더 쉬운 통합
- 메시지 리소스 처리 (국제화에 사용)
- 이벤트 발행
- 웹 애플리케이션에서 사용하기 위한 WebApplicationContext와 같은 애플리케이션 계층별 컨텍스트.
요약하자면, BeanFactory는 구성 프레임워크와 기본 기능을 제공하며, ApplicationContext는 더 많은 엔터프라이즈 관련 기능을 추가합니다. ApplicationContext는 BeanFactory의 완전한 상위 집합으로, 이 장에서는 Spring의 IoC 컨테이너 설명에 독점적으로 사용됩니다. BeanFactory 대신 ApplicationContext를 사용하는 방법에 대한 자세한 내용은 BeanFactory API를 다루는 섹션을 참조하십시오.
Spring에서 애플리케이션의 중추를 형성하고 Spring IoC 컨테이너에 의해 관리되는 객체를 빈(Bean)이라고 합니다. 빈은 Spring IoC 컨테이너에 의해 인스턴스화되고, 조립되고, 관리되는 객체입니다. 그렇지 않으면 빈은 애플리케이션의 많은 객체 중 하나일 뿐입니다. 빈과 그들 사이의 의존성은 컨테이너에서 사용되는 구성 메타데이터에 반영됩니다.
Container Overview
org.springframework.context.ApplicationContext 인터페이스는 Spring IoC 컨테이너를 나타내며, 빈의 인스턴스화, 구성, 조립을 담당합니다. 컨테이너는 구성 메타데이터를 읽어 인스턴스화, 구성 및 조립할 구성 요소에 대한 지침을 받습니다. 구성 메타데이터는 어노테이션이 달린 구성 컴포넌트 클래스, 팩토리 메서드가 있는 구성 클래스, 또는 외부 XML 파일이나 Groovy 스크립트로 표현될 수 있습니다. 이러한 형식 중 어느 것을 사용하더라도 애플리케이션과 구성 컴포넌트 간의 풍부한 상호 의존성을 구성할 수 있습니다.
ApplicationContext 인터페이스의 여러 구현체들은 핵심 Spring의 일부입니다. 독립 실행형(stand-alone) 애플리케이션에서는 AnnotationConfigApplicationContext 또는 ClassPathXmlApplicationContext의 인스턴스를 생성하는 것이 일반적입니다.
대부분의 애플리케이션 시나리오에서는, Spring IoC 컨테이너의 한 개 이상의 인스턴스를 인스턴스화하는 명시적인 사용자 코드가 필요하지 않습니다. 예를 들어, 일반 웹 애플리케이션 시나리오에서는 애플리케이션의 web.xml 파일에 있는 간단한 보일러플레이트 웹 디스크립터 XML만으로 충분합니다(Web Applications을 위한 편리한 ApplicationContext 인스턴스화 참조). Spring Boot 시나리오에서는 일반적인 설정 규칙[convention]에 따라 애플리케이션 컨텍스트가 자동으로 부트스트랩됩니다.
다음 다이어그램은 Spring이 작동하는 방식에 대한 높은 수준의 보기를 보여줍니다. 여러분의 애플리케이션 클래스들은 구성 메타데이터와 결합되므로 ApplicationContext가 생성되고 초기화된 후 완전히 구성되고 실행 가능한 시스템 또는 애플리케이션을 갖게 됩니다.
Configuration Metadata
앞서 언급한 다이어그램에서 알 수 있듯이, Spring IoC 컨테이너는 구성 메타데이터 형태를 사용합니다. 이 구성 메타데이터는 애플리케이션 개발자인 여러분이 Spring 컨테이너에게 애플리케이션의 구성 컴포넌트들을 인스턴스화, 구성 및 조립하는 방법을 지시하는 방식입니다.
Spring IoC 컨테이너 자체는 이 구성 메타데이터가 실제로 작성되는 형식과 완전히 분리[Decoupled]되어 있습니다. 요즘에는 많은 개발자가 Spring 애플리케이션에 대해 Java 기반 Configuration을 선택합니다.
- Annotation-based configuration: 애플리케이션의 컴포넌트 클래스에 Annotation-based 구성 메타데이터를 사용하여 Bean을 정의합니다.
- Java-based configuration: Java 기반 configuration 클래스를 사용하여 애플리케이션 클래스 외부에 Bean을 정의합니다. 이러한 기능을 사용하려면 @Configuration, @Bean, @Import 및 @DependsOn 어노테이을 참조하세요.
Spring 구성은 컨테이너가 관리해야 하는 적어도 하나, 일반적으로 하나 이상의 Bean 정의로 구성됩니다. Java 구성은 일반적으로 @Configuration 클래스 내에서 각각 하나의 Bean 정의에 해당하는 @Bean 어노테이션이 달린 메소드를 사용합니다.
이러한 빈 정의는 애플리케이션을 구성하는 실제 객체에 해당합니다. 일반적으로 서비스 계층 객체, 리포지토리나 데이터 접근 객체(DAO)와 같은 영속성 계층 객체, 웹 컨트롤러와 같은 프레젠테이션 객체, JPA EntityManagerFactory, JMS 큐 등과 같은 인프라 객체를 정의합니다. 일반적으로 도메인 객체와 같은 세분화된 객체는 컨테이너에서 구성하지 않는데, 이는 주로 리포지토리와 비즈니스 로직의 책임으로 도메인 객체를 생성하고 로드하기 때문입니다.
XML as an External Configuration DSL
XML 기반 구성 메타데이터는 이러한 Bean들을 최상위 <beans/> 엘리먼트 내의 <bean/> 엘리먼트로 구성합니다. 다음 예에서는 XML 기반 구성 메타데이터의 기본 구조를 보여줍니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="..."> <1><2>
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
<1> id 속성은 개별 빈 정의를 식별하는 문자열입니다.<2> class 속성은 빈의 타입을 정의하며, 전체 클래스 이름을 사용합니다.id 속성의 값은 공동 작업 객체를 참조하는 데 사용될 수 있습니다. 이 예에는 공동 작업 객체를 참조하기 위한 XML이 표시되지 않습니다. 자세한 내용은 Dependencies을 참조하세요.
컨테이너를 인스턴스화하려면, XML 리소스 파일의 경로를 ClassPathXmlApplicationContext 생성자에 제공해야 하며, 이를 통해 컨테이너는 로컬 파일 시스템, Java CLASSPATH 등 다양한 외부 리소스에서 구성 메타데이터를 로드할 수 있습니다.
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
참고
Spring의 IoC 컨테이너에 대해 배운 후에는 URI 구문에 정의된 위치에서 InputStream을 읽기 위한 편리한 메커니즘을 제공하는 Spring의 리소스 추상화(리소스에 설명됨)에 대해 더 알고 싶을 수도 있습니다. 특히 리소스 경로는 애플리케이션 컨텍스트 및 리소스 경로에 설명된 대로 애플리케이션 컨텍스트를 구성하는 데 사용됩니다.
다음 예는 서비스 계층 객체(services.xml) 구성 파일을 보여줍니다:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
다음 예에서는 데이터 액세스 객체 daos.xml 파일을 보여줍니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountDao"
class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for data access objects go here -->
</beans>
앞의 예에서 서비스 계층은 PetStoreServiceImpl 클래스와 JpaAccountDao 및 JpaItemDao 유형(JPA 객체 관계형 매핑 표준 기반)의 두 데이터 액세스 객체로 구성됩니다. 속성 이름 요소는 JavaBean 속성의 이름을 참조하고, ref 요소는 다른 빈 정의의 이름을 참조합니다. id와 ref 요소 간의 이러한 연결은 공동 작업 개체 간의 종속성을 표현합니다. 개체의 종속성 구성에 대한 자세한 내용은 Dependencies를 참조하세요.
Composing XML-based Configuration Metadata
빈 정의가 여러 XML 파일에 걸쳐 있는 것이 유용할 수 있습니다. 종종 각 개별 XML 구성 파일은 아키텍처의 논리적 계층 또는 모듈을 나타냅니다.
ClassPathXmlApplicationContext 생성자를 사용하여 XML 코드에서 빈 정의를 로드할 수 있습니다. 이 생성자는 이전 섹션에서 보여준 것처럼 여러 리소스 위치를 허용합니다. 또는 <import/> 엘리먼트를 한 번 또는 여러 번 사용하여 다른 파일에서 빈 정의를 로드할 수 있습니다. 다음 예는 그 방법을 보여줍니다:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
앞의 예제에서 외부 빈 정의는 세 개의 파일인 services.xml, messageSource.xml, 그리고 themeSource.xml에서 로드됩니다. 모든 경로는 임포트하는 정의 파일을 기준으로 상대 경로이므로, services.xml은 임포트하는 파일과 동일한 디렉토리 또는 클래스패스 위치에 있어야 하고, messageSource.xml과 themeSource.xml은 임포트하는 파일의 위치 아래의 리소스 위치에 있어야 합니다. 보시다시피, 앞에 있는 슬래시는 무시됩니다. 그러나 이러한 경로가 상대적이기 때문에, 슬래시를 전혀 사용하지 않는 것이 더 나은 방법입니다. 임포트되는 파일의 내용, 최상위 <beans/> 엘리먼트를 포함하여, Spring 스키마에 따라 유효한 XML 빈 정의여야 합니다.
참고:
상대 "../" 경로를 사용하여 상위 디렉터리의 파일을 참조하는 것이 가능하지만 권장되지는 않습니다. 이렇게 하면 현재 애플리케이션 외부에 있는 파일에 대한 종속성이 생성됩니다. 특히 이 참조는 런타임 확인 프로세스가 "가장 가까운" 클래스 경로 루트를 선택한 다음 해당 상위 디렉터리를 조사하는 classpath: URL(예: classpath:../services.xml)에는 권장되지 않습니다. 클래스 경로 구성 변경으로 인해 다른 잘못된 디렉터리가 선택될 수 있습니다.
항상 상대 경로 대신 완전한 리소스 위치를 사용할 수 있습니다. 예를 들어, file:C:/config/services.xml 또는 classpath:/config/services.xml을 사용할 수 있습니다. 그러나 이렇게 하면 애플리케이션의 구성을 특정 절대 위치에 결합하게 된다는 점을 유의해야 합니다. 일반적으로 이러한 절대 위치에 대해 간접 참조를 유지하는 것이 바람직합니다. 예를 들어, 런타임에 JVM 시스템 속성을 통해 해결되는 "${...}" 플레이스홀더를 사용하는 방식이 있습니다.
네임스페이스 자체는 import 지시문 기능을 제공합니다. 일반 빈 정의 이상의 추가 구성 기능은 Spring이 제공하는 XML 네임스페이스 선택(예: context 및 util 네임스페이스)에서 사용할 수 있습니다.
Using the Container
ApplicationContext는 다양한 빈과 그들의 dependencies을 등록하고 유지할 수 있는 고급 팩토리 인터페이스입니다. T getBean(String name, Class<T> requiredType) 메서드를 사용하여 빈 인스턴스를 가져올 수 있습니다.
ApplicationContext를 사용하면 빈 정의를 읽고 접근할 수 있습니다. 다음 예제에서 보여줍니다:
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
위 코드처럼, getBean을 사용하여 빈 인스턴스를 가져올 수 있습니다. ApplicationContext 인터페이스에는 빈을 가져오는 몇 가지 다른 메서드가 있지만, 이상적으로는 애플리케이션 코드가 이 메서드들을 전혀 사용해서는 안 됩니다. 실제로 애플리케이션 코드는 getBean() 메서드를 전혀 호출하지 않아야 하며, 따라서 Spring API에 대한 의존성이 전혀 없어야 합니다. 예를 들어, Spring의 웹 프레임워크 통합은 컨트롤러 및 JSF 관리 빈과 같은 다양한 웹 프레임워크 구성 요소에 대한 의존성 주입을 제공하여 메타데이터(예: 자동 연결 어노테이션)를 통해 특정 빈에 대한 의존성을 선언할 수 있게 합니다.
[출처: The IoC Container]
'Spring Framework > Spring IoC' 카테고리의 다른 글
Using @Autowired (0) | 2023.12.10 |
---|---|
Dependencies and Configuration in Detail (0) | 2023.12.10 |
Fine-tuning Annotation-based Autowiring with @Primary (0) | 2023.07.08 |
Dependency Injection of Spring Framework (0) | 2023.05.01 |
Bean Definition Inheritance (0) | 2023.04.28 |