IoC 컨테이너
이 장에서는 Spring의 제어 반전(IoC) 컨테이너를 다룹니다.
섹션 요약
Spring IoC 컨테이너와 Bean 소개
이 장에서는 제어의 역전(IoC) 원칙을 구현하는 Spring 프레임워크에 대해 설명합니다. 의존성 주입(DI)은 객체가 생성자 인수, 팩토리 메서드의 인수 또는 객체 인스턴스가 생성되거나 팩토리 메서드에서 반환된 후 객체 인스턴스에 설정된 속성을 통해서만 해당 종속성(즉, 함께 작업하는 다른 객체)을 정의하는 특수한 형태의 IoC입니다. 그런 다음 IoC 컨테이너는 빈을 생성할 때 이러한 종속성을 주입합니다. 이 프로세스는 기본적으로 클래스의 직접 구성 또는 서비스 로케이터 패턴과 같은 메커니즘을 사용하여 종속성의 인스턴스화 또는 위치를 제어하는 빈 자체의 역방향(따라서 이름, 제어의 역전)입니다.
Org.springframework.beans 및 org.springframework.context 패키지는 Spring Framework의 IoC 컨테이너의 기반입니다.BeanFactory인터페이스는 모든 유형의 객체를 관리할 수 있는 고급 구성 메커니즘을 제공합니다.ApplicationContext는 BeanFactory의 하위 인터페이스입니다. 추가합니다:
- Spring의 AOP 기능과의 손쉬운 통합
- 메시지 리소스 처리(국제화에 사용)
- 이벤트 게시
- 웹 애플리케이션에서 사용하기 위한 WebApplicationContext와같은 애플리케이션 계층별 컨텍스트.
간단히 말해, BeanFactory는 구성 프레임워크와 기본 기능을 제공하며, ApplicationContext는 더 많은 기업별 기능을 추가합니다.ApplicationContext는 BeanFactory의 완전한 상위 집합이며, 이 장에서는 Spring의 IoC 컨테이너에 대한 설명에서 독점적으로 사용됩니다. ApplicationContext 대신 BeanFactory를 사용하는 방법에 대한 자세한 내용은BeanFactory API를 다루는 섹션을 참조하세요.
Spring에서는 애플리케이션의 백본을 형성하고 Spring IoC 컨테이너에 의해 관리되는 객체를 Bean이라고 합니다. 빈은 Spring IoC 컨테이너에 의해 인스턴스화, 어셈블 및 관리되는 객체입니다. 그렇지 않으면 빈은 애플리케이션의 많은 객체 중 하나에 불과합니다. 빈과 빈 간의 종속성은 컨테이너에서 사용하는 구성 메타데이터에 반영됩니다.
Container Overview
Org.springframework.context.ApplicationContext 인터페이스는 Spring IoC 컨테이너를 나타내며 빈의 인스턴스화, 구성 및 어셈블리를 담당합니다. 컨테이너는 구성 메타데이터를 읽음으로써 인스턴스화, 구성 및 어셈블할 구성 요소에 대한 지침을 얻습니다. 구성 메타데이터는 주석이 달린 컴포넌트 클래스, 팩토리 메서드가 있는 구성 클래스, 외부 XML 파일 또는 Groovy 스크립트로 표현될 수 있습니다. 어떤 형식을 사용하든 애플리케이션과 해당 컴포넌트 간의 풍부한 상호 의존성을 구성할 수 있습니다.
ApplicationContext 인터페이스의 여러 구현은 핵심 Spring의 일부입니다. 독립형 애플리케이션에서는AnnotationConfigApplicationContext또는 ClassPathXmlApplicationContext의 인스턴스를 생성하는 것이 일반적입니다.
대부분의 애플리케이션 시나리오에서는 하나 이상의 Spring IoC 컨테이너 인스턴스를 인스턴스화하기 위해 명시적인 사용자 코드가 필요하지 않습니다. 예를 들어, 일반 웹 애플리케이션 시나리오에서는 애플리케이션의 web.xml 파일에 있는 간단한 상용구 웹 설명자 XML로 충분합니다(웹 애플리케이션을 위한 편리한 ApplicationContext 인스턴스화 참조). Spring Boot 시나리오에서는 일반적인 설정 규칙에 따라 애플리케이션 컨텍스트가 암시적으로 부트스트랩됩니다.
다음 다이어그램은 Spring이 어떻게 작동하는지에 대한 개략적인 보기를 보여줍니다. 애플리케이션 클래스는 구성 메타데이터와 결합되어 애플리케이션 컨텍스트가 생성되고 초기화되면 완전히 구성되고 실행 가능한 시스템 또는 애플리케이션을 갖게 됩니다.
Configuration Metadata
앞의 다이어그램에서 볼 수 있듯이, Spring IoC 컨테이너는 일종의 구성 메타데이터를 사용합니다. 이 구성 메타데이터는 애플리케이션 개발자가 애플리케이션의 구성 요소를 인스턴스화, 구성 및 어셈블하도록 Spring 컨테이너에 지시하는 방법을 나타냅니다.
Spring IoC 컨테이너 자체는 이 구성 메타데이터가 실제로 작성되는 형식과 완전히 분리되어 있습니다. 요즘에는 많은 개발자들이 Spring 애플리케이션을 위해Java 기반 구성을 선택합니다:
- 어노테이션 기반 구성: 애플리케이션의 컴포넌트 클래스에서 어노테이션 기반 구성 메타데이터를 사용하여 빈을 정의합니다.
- Java 기반 구성: Java 기반 구성 클래스를 사용하여 애플리케이션 클래스 외부에서 빈을 정의합니다. 이러한 기능을 사용하려면@Configuration,@Bean,@Import 및 @DependsOn 어노테이션을 참조하세요.
Spring 구성은 컨테이너가 관리해야 하는 하나 이상의 빈 정의로 구성되며, 일반적으로 하나 이상의 빈 정의로 구성됩니다. Java 구성은 일반적으로 @Configuration 클래스 내에서 @Bean 어노테이션 메서드를 사용하며, 각 메서드는 하나의 빈 정의에 해당합니다.
이러한 빈 정의는 애플리케이션을 구성하는 실제 객체에 해당합니다. 일반적으로 서비스 계층 객체, 리포지토리 또는 DAO(데이터 액세스 객체)와 같은 지속성 계층 객체, 웹 컨트롤러와 같은 프레젠테이션 객체, JPA EntityManagerFactory, JMS 큐 등과 같은 인프라 객체를 정의합니다. 일반적으로 도메인 객체를 생성하고 로드하는 것은 리포지토리 및 비즈니스 로직의 책임이므로 일반적으로 컨테이너에서 세분화된 도메인 객체를 구성하지는 않습니다.
외부 구성 DSL로서의 XML
XML 기반 구성 메타데이터는 이러한 빈을 최상위 <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="...">
<!-- 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>
Id 속성은 개별 빈 정의를 식별하는 문자열입니다. | |
Class 속성은 빈의 유형을 정의하며 정규화된 클래스 이름을 사용합니다. |
Id 속성의 값은 공동 작업 객체를 참조하는 데 사용할 수 있습니다. 이 예에서는 공동 작업 객체를 참조하기 위한 XML은 표시되지 않습니다. 자세한 내용은종속성을 참조하세요.
컨테이너를 인스턴스화하려면 컨테이너가 로컬 파일 시스템, Java 클래스 경로 등과 같은 다양한 외부 리소스에서 구성 메타데이터를 로드할 수 있도록 XML 리소스 파일의 위치 경로를 ClassPathXmlApplicationContext 생성자에 하나 이상의 경로를 제공해야 합니다.
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
Spring의 IoC 컨테이너에 대해 배운 후에는 URI 구문에 정의된 위치에서 InputStream을 읽기 위한 편리한 메커니즘을 제공하는 Spring의Resource 추상화(Resources에 설명됨)에 대해 자세히 알아보고 싶을 수 있습니다. 특히 리소스 경로는 애플리케이션 컨텍스트 및 리소스 경로에 설명된 대로 애플리케이션 컨텍스트를 구성하는 데 사용됩니다.
|
다음 예는 서비스 계층 개체 (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 클래스와 (JPA 객체 관계형 매핑 표준에 기반한) JpaAccountDao 및 JpaItemDao 유형의 데이터 액세스 객체 두 개로 구성됩니다. 속성 이름 요소는 JavaBean 속성의 이름을 참조하고 참조 요소는 다른 빈 정의의 이름을 참조합니다. Id 요소와 ref 요소 사이의 이러한 연결은 공동 작업하는 개체 간의 종속성을 나타냅니다. 객체의 종속성 구성에 대한 자세한 내용은종속성을 참조하세요.
XML 기반 구성 메타데이터 구성하기
빈 정의가 여러 XML 파일에 걸쳐 있으면 유용할 수 있습니다. 종종 각 개별 XML 구성 파일은 아키텍처의 논리적 계층 또는 모듈을 나타냅니다.
XML 조각에서 빈 정의를 로드하기 위해 ClassPathXmlApplicationContext 생성자를 사용할 수 있습니다. 이 생성자는이전 섹션에서 설명한 것처럼 여러 리소스 위치를 사용합니다. 또는 <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 빈 정의여야 합니다.
상대 "../" 경로를 사용하여 상위 디렉터리의 파일을 참조하는 것은 가능하지만 권장되지는 않습니다. 이렇게 하면 현재 애플리케이션 외부에 있는 파일에 대한 종속성이 생성됩니다. 특히 클래스 경로에는 이 참조를 사용하지 않는 것이 좋습니다: URL(예: classpath:../services.xml)의 경우 런타임 확인 프로세스에서 "가장 가까운" 클래스 경로 루트를 선택한 다음 상위 디렉터리를 찾습니다. 클래스경로 구성을 변경하면 다른 잘못된 디렉터리가 선택될 수 있습니다.
상대 경로 대신 항상 정규화된 리소스 위치를 사용할 수 있습니다(예: file:C:/config/services.xml 또는 classpath:/config/services.xml). 하지만 애플리케이션의 구성을 특정 절대 위치에 연결한다는 점에 유의하세요. 일반적으로 이러한 절대 위치는 런타임에 JVM 시스템 속성에 대해 확인되는 "${...}" 자리 표시자를 통해 간접적으로 지정하는 것이 좋습니다.
|
네임스페이스 자체는 임포트 지시어 기능을 제공합니다. 일반 빈 정의 이외의 추가 구성 기능은 Spring에서 제공하는 다양한 XML 네임스페이스(예: 컨텍스트 및 util 네임스페이스)에서 사용할 수 있습니다.
그루비 빈 정의 DSL
외부화된 구성 메타데이터의 또 다른 예로, 빈 정의는 Grails 프레임워크에서 알려진 것처럼 Spring의 Groovy Bean Definition DSL로 표현할 수도 있습니다. 일반적으로 이러한 구성은 다음 예와 같은 구조의 ".groovy" 파일에 저장됩니다:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
이 구성 스타일은 XML 빈 정의와 거의 동일하며 Spring의 XML 구성 네임스페이스도 지원합니다. 또한 importBeans 지시어를 통해 XML 빈 정의 파일을 가져올 수 있습니다.
Using the Container
ApplicationContext는 다양한 빈과 그 종속성의 레지스트리를 유지할 수 있는 고급 팩토리를 위한 인터페이스입니다.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();
Groovy 구성을 사용하면 부트스트랩은 매우 유사하게 보입니다. 여기에는 Groovy를 인식하는 다른 컨텍스트 구현 클래스가 있습니다(XML 빈 정의도 이해함). 다음 예는 Groovy 구성을 보여줍니다:
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
가장 유연한 변형은 다음 예제에서 볼 수 있듯이 XML 파일용 XmlBeanDefinitionReader와 같은 리더 델리게이트와 함께 사용하는 GenericApplicationContext입니다:
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
다음 예제에서 볼 수 있듯이 Groovy 파일용 GroovyBeanDefinitionReader를 사용할 수도 있습니다:
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
이러한 리더 델리게이트를 동일한 ApplicationContext에서 혼합 및 일치시켜 다양한 구성 소스에서 빈 정의를 읽을 수 있습니다.
그런 다음 getBean을 사용하여 빈의 인스턴스를 검색할 수 있습니다. ApplicationContext인터페이스에는 빈을 검색하는 몇 가지 다른 메서드가 있지만, 이상적으로는 애플리케이션 코드에서 이러한 메서드를 사용해서는 안 됩니다. 실제로 애플리케이션 코드에는getBean() 메서드에 대한 호출이 전혀 없어야 하며, 따라서 Spring API에 대한 종속성이 전혀 없어야 합니다. 예를 들어, Spring과 웹 프레임워크의 통합은 컨트롤러 및 JSF 관리 빈과 같은 다양한 웹 프레임워크 구성 요소에 대한 의존성 주입을 제공하여 메타데이터(예: 자동 배선 주석)를 통해 특정 빈에 대한 의존성을 선언할 수 있게 해줍니다.
Bean Overview
Spring IoC 컨테이너는 하나 이상의 빈을 관리합니다. 이러한 빈은 컨테이너에 제공하는 구성 메타데이터(예: XML<bean/> 정의의 형태)로 생성됩니다.
컨테이너 자체 내에서 이러한 빈 정의는 다음과 같은 메타데이터를 포함하는 BeanDefinition객체로 표시됩니다(다른 정보 중에서도):
- 패키지 한정 클래스 이름: 일반적으로 정의되는 빈의 실제 구현 클래스입니다.
- 빈 동작 구성 요소: 컨테이너에서 빈이 어떻게 동작해야 하는지(범위, 라이프사이클 콜백 등)를 명시합니다.
- 빈이 작업을 수행하는 데 필요한 다른 빈에 대한 참조. 이러한 참조를 공동 작업자 또는 종속성이라고도 합니다.
- 새로 생성된 객체에 설정할 기타 구성 설정(예: 풀의 크기 제한 또는 연결 풀을 관리하는 빈에서 사용할 연결 수).
이 메타데이터는 각 빈 정의를 구성하는 속성 집합으로 변환됩니다. 다음 표에서는 이러한 속성에 대해 설명합니다:
클래스 | 인스턴스화 빈 |
Name | 빈 이름 지정 |
범위 | 빈 범위 |
생성자 인자 | 종속성 주입 |
속성 | 의존성 주입 |
자동 배선 모드 | 자동 배선 공동 작업자 |
지연 초기화 모드 | 지연 초기화된 빈 |
초기화 방법 | 초기화 콜백 |
소멸 메서드 | 소멸 콜백 |
특정 빈을 생성하는 방법에 대한 정보를 포함하는 빈 정의 외에도, ApplicationContext 구현은 컨테이너 외부에서 (사용자가) 생성한 기존 객체를 등록할 수 있도록 허용합니다. 이 작업은 getBeanFactory() 메서드를 통해 애플리케이션 컨텍스트의 BeanFactory에 액세스하여 수행되며, 이 메서드는 DefaultListableBeanFactory 구현을 반환합니다. DefaultListableBeanFactory는 registerSingleton(..) 및 registerBeanDefinition(..) 메서드를 통해 이 등록을 지원합니다. 그러나 일반적인 애플리케이션은 일반 빈 정의 메타데이터를 통해 정의된 빈으로만 작동합니다.
빈 메타데이터와 수동으로 제공된 싱글톤 인스턴스는 가능한 한 빨리 등록해야 컨테이너가 자동 배선 및 기타 인트로스펙션 단계에서 이를 적절히 추론할 수 있습니다. 기존 메타데이터와 기존 싱글톤 인스턴스를 재정의하는 것은 어느 정도 지원되지만, 런타임에 (팩토리에 대한 실시간 액세스와 동시에) 새 빈을 등록하는 것은 공식적으로 지원되지 않으며 동시 액세스 예외, 빈 컨테이너의 일관되지 않은 상태 또는 두 가지 모두로 이어질 수 있습니다.
|
Overriding Beans
빈 재정의는 이미 할당된 식별자를 사용하여 빈이 등록될 때 발생합니다. 빈 재정의는 가능하지만 구성을 읽기 어렵게 만들며 이 기능은 향후 릴리스에서 더 이상 사용되지 않습니다.
빈 재정의 기능을 완전히 사용하지 않으려면 새로 고침하기 전에 ApplicationContext에서 allowBeanDefinitionOverriding플래그를 false로 설정하면 됩니다. 이러한 설정에서는 빈 재정의가 사용되면 예외가 발생합니다.
기본적으로 컨테이너는 모든 빈 오버라이딩을 INFO 수준에서 기록하므로 사용자가 그에 따라 구성을 조정할 수 있습니다. 권장되지는 않지만, allowBeanDefinitionOverriding 플래그를 true로 설정하여 이러한 로그를 무음화할 수 있습니다.
Java 구성을 사용하는 경우,@Bean 메서드의 반환 유형이 해당 빈 클래스와 일치하는 한 해당 @Bean 메서드는 항상 동일한 구성 요소 이름을 가진 스캔된 빈 클래스를 자동으로 재정의합니다. 즉, 컨테이너가 빈 클래스에 미리 선언된 생성자 대신 @Bean 팩토리 메서드를 호출한다는 의미입니다.
Naming Beans
모든 빈에는 하나 이상의 식별자가 있습니다. 이러한 식별자는 빈을 호스팅하는 컨테이너 내에서 고유해야 합니다. 빈에는 일반적으로 하나의 식별자만 있습니다. 그러나 두 개 이상의 식별자가 필요한 경우 여분의 식별자는 별칭으로 간주할 수 있습니다.
XML 기반 구성 메타데이터에서는 id 속성, name 속성 또는 둘 다를 사용하여 빈 식별자를 지정합니다. Id 속성을 사용하면 정확히 하나의 id를 지정할 수 있습니다. 일반적으로 이러한 이름은 영숫자('myBean', 'someService' 등)이지만 특수 문자도 포함할 수 있습니다. 빈의 다른 별칭을 도입하려는 경우 쉼표(,), 세미콜론(;) 또는 공백으로 구분하여 이름 속성에 별칭을 지정할 수도 있습니다. Id 속성은xsd:string 유형으로 정의되지만, 빈 ID 고유성은 XML 파서가 아니라 컨테이너에 의해 적용됩니다.
빈의 이름이나 id를 제공할 필요는 없습니다.이름이나 ID를 명시적으로 제공하지 않으면 컨테이너가 해당 빈의 고유 이름을 생성합니다. 그러나 ref 요소 또는 서비스 로케이터 스타일 조회를 사용하여 해당 빈을 이름으로 참조하려면 이름을 제공해야 합니다. 이름을 제공하지 않는 동기는 내부 빈및 자동 배선 협력자 사용과 관련이 있습니다.
빈 이름을 지정할 때 인스턴스 필드 이름에 표준 Java 규칙을 사용하는 것이 규칙입니다. 즉, 빈 이름은 소문자로 시작하고 거기서부터 대소문자를 사용합니다. 이러한 이름의 예로는 계정 관리자,계정 서비스, 사용자 다오, 로그인 컨트롤러 등이 있습니다.
일관되게 빈 이름을 지정하면 구성을 더 쉽게 읽고 이해할 수 있습니다. 또한 Spring AOP를 사용하는 경우 이름으로 관련된 빈 집합에 조언을 적용할 때 많은 도움이 됩니다.
클래스 경로에서 컴포넌트 스캔을 사용하면 Spring은 앞서 설명한 규칙(기본적으로 간단한 클래스 이름을 가져와 첫 글자를 소문자로 바꾸는 것)에 따라 이름이 지정되지 않은 컴포넌트에 대한 빈 이름을 생성합니다. 그러나 문자가 두 개 이상이고 첫 번째와 두 번째 문자가 모두 대문자인 (비정상적인) 특수한 경우에는 원래의 대소문자가 유지됩니다. 이는 java.beans.Introspector.decapitalize에 정의된 것과 동일한 규칙입니다(여기서 Spring이 사용함) |
빈 정의 외부에서 빈 앨리어싱하기
빈 정의 자체에서 id 속성에 지정된 최대 하나의 이름과 이름 속성에 있는 다른 이름을 조합하여 빈에 대해 둘 이상의 이름을 제공할 수 있습니다. 이러한 이름은 동일한 빈에 대한 동등한 별칭이 될 수 있으며, 애플리케이션의 각 구성 요소가 해당 구성 요소 자체에 특정한 빈 이름을 사용하여 공통 종속성을 참조하도록 하는 등의 일부 상황에 유용합니다.
그러나 빈이 실제로 정의된 곳에 모든 별칭을 지정하는 것이 항상 적절한 것은 아닙니다. 때로는 다른 곳에 정의된 빈에 대한 별칭을 도입하는 것이 바람직할 때가 있습니다. 이는 일반적으로 구성이 각 하위 시스템으로 분할되어 있고 각 하위 시스템에 고유한 객체 정의 집합이 있는 대규모 시스템에서 발생합니다. XML 기반 구성 메타데이터에서는 <alias/> 요소를 사용하여 이를 수행할 수 있습니다. 다음 예는 그 방법을 보여줍니다:
<alias name="fromName" alias="toName"/>
이 경우, 동일한 컨테이너에 있는 fromName이라는 이름의 빈은 이 별칭 정의를 사용한 후에 toName으로 참조될 수도 있습니다.
예를 들어, 하위 시스템 A에 대한 구성 메타데이터는 하위 시스템A-dataSource라는 이름으로 데이터 소스를 참조할 수 있습니다. 하위 시스템 B에 대한 구성 메타데이터는 하위 시스템B-dataSource라는 이름으로 데이터 소스를 참조할 수 있습니다. 이 두 하위 시스템을 모두 사용하는 메인 애플리케이션을 구성할 때 메인 애플리케이션은 myApp-dataSource라는 이름으로 데이터소스를 참조합니다. 세 이름이 모두 동일한 개체를 참조하도록 하려면 구성 메타데이터에 다음 별칭 정의를 추가하면 됩니다:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
이제 각 구성 요소와 주 애플리케이션은 고유하고 다른 정의와 충돌하지 않도록 보장되는 이름을 통해 데이터소스를 참조할 수 있지만(효과적으로 네임스페이스 생성), 동일한 빈을 참조할 수 있습니다.
Java 구성을 사용하는 경우 @Bean 어노테이션을 사용하여 별칭을 제공할 수 있습니다. 자세한 내용은 @Bean 어노테이션 사용을 참조하세요.
Instantiating Beans
빈 정의는 본질적으로 하나 이상의 객체를 생성하기 위한 레시피입니다. 컨테이너는 요청 시 명명된 빈의 레시피를 살펴보고 해당 빈 정의로 캡슐화된 구성 메타데이터를 사용하여 실제 객체를 생성(또는 획득)합니다.
XML 기반 구성 메타데이터를 사용하는 경우, 인스턴스화할 객체의 유형(또는 클래스)을 <bean/> 요소의 클래스 속성에 지정합니다. 이클래스 속성(내부적으로는 BeanDefinition인스턴스의 Class 속성)은 일반적으로 필수입니다. (예외에 대해서는인스턴스 팩토리 메서드를 사용한 인스턴스화 및 Bean 정의 상속을 참조하십시오.) Class 속성은 두 가지 방법 중 하나로 사용할 수 있습니다:
- 일반적으로 컨테이너 자체가 생성자를 반사적으로 호출하여 빈을 직접 생성하는 경우, 새 연산자를 사용하는 Java 코드와 어느 정도 동일하게 생성할 빈 클래스를 지정합니다.
- 컨테이너가 클래스에서정적 팩토리 메서드를 호출하여 빈을 생성하는 덜 일반적인 경우, 객체를 생성하기 위해 호출되는 정적 팩토리 메서드가 포함된 실제 클래스를 지정합니다. 정적 팩토리 메서드 호출에서 반환되는 객체 유형은 동일한 클래스이거나 완전히 다른 클래스일 수 있습니다.
중첩된 클래스에 대한 빈 정의를 구성하려는 경우 중첩된 클래스의 이진 이름 또는 소스 이름을 사용할 수 있습니다.
예를 들어 com.example 패키지에 SomeThing이라는 클래스가 있고 이 SomeThing 클래스에 OtherThing이라는 정적 중첩 클래스가 있는 경우 달러 기호($) 또는 점(.)으로 구분할 수 있습니다. 따라서 빈 정의에서 클래스 속성의 값은 com.example.SomeThing$OtherThing 또는com.example.SomeThing.OtherThing이 됩니다.
생성자를 사용한 인스턴스화
생성자 접근 방식으로 빈을 생성하면 모든 일반 클래스가 Spring에서 사용할 수 있고 호환됩니다. 즉, 개발 중인 클래스는 특정 인터페이스를 구현하거나 특정 방식으로 코딩할 필요가 없습니다. 단순히 빈 클래스를 지정하는 것으로 충분합니다. 그러나 특정 빈에 사용하는 IoC 유형에 따라 기본(빈) 생성자가 필요할 수 있습니다.
Spring IoC 컨테이너는 관리하고자 하는 거의 모든 클래스를 관리할 수 있습니다. 이는 실제 JavaBean 관리에만 국한되지 않습니다. 대부분의 Spring 사용자는 기본(인수가 없는) 생성자와 컨테이너의 속성을 따라 모델링된 적절한 세터 및 게터만 있는 실제 JavaBean을 선호합니다. 컨테이너에 더 이색적인 비빈 스타일 클래스를 포함할 수도 있습니다. 예를 들어, JavaBean 사양을 전혀 준수하지 않는 레거시 연결 풀을 사용해야 하는 경우 Spring에서 이를 관리할 수 있습니다.
XML 기반 구성 메타데이터를 사용하면 다음과 같이 빈 클래스를 지정할 수 있습니다:
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
생성자에 인수를 제공하는 메커니즘(필요한 경우)과 객체가 생성된 후 객체 인스턴스 속성을 설정하는 메커니즘에 대한 자세한 내용은 종속성주입을 참조하세요.
생성자 인자의 경우 컨테이너는 오버로드된 여러 생성자 중에서 해당 생성자를 선택할 수 있습니다. 즉, 모호성을 피하려면 생성자 서명을 가능한 한 간단하게 유지하는 것이 좋습니다 |
정적 팩토리 메서드를 사용한 인스턴스화
정적 팩토리 메서드를 사용하여 생성하는 빈을 정의할 때는 클래스속성을 사용하여 정적 팩토리 메서드가 포함된 클래스를 지정하고 factory-method라는 속성을 사용하여 팩토리 메서드 자체의 이름을 지정합니다. 나중에 설명하는 대로 선택적 인수를 사용하여 이 메서드를 호출하고 생성자를 통해 생성된 것처럼 처리되는 라이브 객체를 반환할 수 있어야 합니다. 이러한 빈 정의의 한 가지 용도는 레거시 코드에서 정적 팩토리를 호출하는 것입니다.
다음 빈 정의는 팩토리 메서드를 호출하여 빈을 생성하도록 지정합니다. 이 정의는 반환되는 객체의 유형(클래스)을 지정하지 않고 팩토리 메서드가 포함된 클래스를 지정합니다. 이 예제에서createInstance() 메서드는 정적 메서드여야 합니다. 다음 예제는 팩토리 메서드를 지정하는 방법을 보여줍니다:
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
다음 예제는 앞의 빈 정의와 함께 작동하는 클래스를 보여줍니다:
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
팩토리 메서드에 (선택적) 인수를 제공하고 객체가 팩토리에서 반환된 후 객체 인스턴스 속성을 설정하는 메커니즘에 대한 자세한 내용은 종속성 및 구성 상세 정보를 참조하세요.
팩토리 메서드 인수의 경우 컨테이너는 같은 이름의 여러 오버로드된 메서드 중에서 해당 메서드를 선택할 수 있습니다. 즉, 모호함을 피하려면 팩토리 메서드 서명을 가능한 한 간단하게 유지하는 것이 좋습니다 |
팩토리 메서드 오버로드로 인해 문제가 되는 대표적인 사례는 모의 메서드 오버로드가 많은 Mockito입니다. 가능한 가장 구체적인 모의 메서드 변형을 선택하세요:
|
인스턴스 팩토리 메서드를 사용한 인스턴스화
정적 팩토리 메서드를통한 인스턴스화와 유사하게 인스턴스 팩토리 메서드를 사용한 인스턴스화는 컨테이너에서 기존 빈의 비정적 메서드를 호출하여 새 빈을 생성합니다. 이 메커니즘을 사용하려면 클래스 속성을 비워두고 factory-bean 속성에서 객체를 생성하기 위해 호출할 인스턴스 메서드가 포함된 현재(또는 부모 또는 상위) 컨테이너의 빈 이름을 지정합니다. Factory-method 속성을 사용하여 팩토리 메서드 자체의 이름을 설정합니다. 다음 예는 이러한 빈을 구성하는 방법을 보여줍니다:
<!-- the factory bean, which contains a method called createClientServiceInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
다음 예제는 해당 클래스를 보여줍니다:
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
다음 예제에서 볼 수 있듯이 하나의 팩토리 클래스는 둘 이상의 팩토리 메서드를 보유할 수도 있습니다:
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
<bean id="accountService"
factory-bean="serviceLocator"
factory-method="createAccountServiceInstance"/>
다음 예제는 해당 클래스를 보여줍니다:
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
이 접근 방식은 의존성 주입(DI)을 통해 팩토리 빈 자체를 관리하고 구성할 수 있음을 보여줍니다. 자세한 내용은 의존성 및 구성을 참조하십시오.
Spring 문서에서 "팩토리 빈"은 Spring 컨테이너에 구성되고인스턴스 또는정적 팩토리 메서드를 통해 객체를 생성하는 빈을 의미합니다. 이와 대조적으로FactoryBean (대문자로 표기된 것을 주목하세요)은 Spring 전용FactoryBean 구현 클래스를 의미합니다 |
Bean의 런타임 유형 결정하기
특정 빈의 런타임 유형은 결정하기 어렵지 않습니다. 빈 메타데이터 정의에서 지정된 클래스는 초기 클래스 참조일 뿐이며, 선언된 팩토리 메서드와 결합되거나 FactoryBean 클래스가 되어 빈의 런타임 유형이 달라지거나 인스턴스 수준 팩토리 메서드의 경우 전혀 설정되지 않을 수 있습니다(대신 지정된 팩토리-빈 이름을 통해 확인됨). 또한 AOP 프록시는 대상 빈의 실제 유형(구현된 인터페이스만)이 제한적으로 노출되는 인터페이스 기반 프록시로 빈 인스턴스를 래핑할 수 있습니다.
특정 빈의 실제 런타임 유형을 알아내는 권장 방법은 지정된 빈 이름에 대해 BeanFactory.getType을 호출하는 것입니다. 이는 위의 모든 경우를 고려하여 동일한 빈 이름에 대해 BeanFactory.getBean 호출이 반환할 객체 유형을 반환합니다.
종속성
일반적인 엔터프라이즈 애플리케이션은 단일 객체(또는 Spring 용어로 빈)로 구성되지 않습니다. 가장 단순한 애플리케이션조차도 최종 사용자에게 일관된 애플리케이션으로 보이기 위해 함께 작동하는 몇 가지 객체가 있습니다. 다음 섹션에서는 독립적으로 존재하는 여러 개의 빈 정의를 정의하는 방법에서 객체가 협업하여 목표를 달성하는 완전히 실현된 애플리케이션으로 전환하는 방법에 대해 설명합니다.
Dependency Injection
종속성 주입(DI)은 객체가 생성자 인수, 팩토리 메서드의 인수 또는 객체 인스턴스가 생성되거나 팩토리 메서드에서 반환된 후 객체 인스턴스에 설정된 속성을 통해서만 종속성(즉, 함께 작동하는 다른 객체)을 정의하는 프로세스입니다. 그런 다음 컨테이너는 빈을 생성할 때 이러한 종속성을 주입합니다. 이 프로세스는 기본적으로 클래스의 직접 구성 또는 서비스 로케이터 패턴을 사용하여 빈 자체가 종속성의 인스턴스화 또는 위치를 자체적으로 제어하는 역방향(따라서 이름, 제어의 역전)입니다.
DI 원칙을 사용하면 코드가 더 깔끔해지며, 객체에 종속성이 제공될 때 디커플링이 더 효과적입니다. 객체는 종속성을 조회하지 않으며 종속성의 위치나 클래스를 알지 못합니다. 결과적으로 클래스를 테스트하기가 더 쉬워지며, 특히 종속성이 인터페이스나 추상 베이스 클래스에 있는 경우 단위 테스트에서 스텁 또는 모의 구현을 사용할 수 있습니다.
DI는 크게 두 가지 변형이 있습니다: 생성자 기반 종속성 주입과 설정자 기반 종속성 주입입니다.
Constructor-based Dependency Injection
생성자 기반 DI는 컨테이너가 각각 종속성을 나타내는 여러 인수를 사용하여 생성자를 호출함으로써 수행됩니다. 특정 인수를 사용하여 정적 팩토리 메서드를 호출하여 빈을 생성하는 것은 거의 동일하며, 이 설명에서는 생성자와 정적 팩토리 메서드에 대한 인수를 비슷하게 취급합니다. 다음 예제는 생성자 주입으로만 종속성을 주입할 수 있는 클래스를 보여줍니다:
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private final MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
이 클래스에는 특별한 것이 없습니다. 컨테이너 특정 인터페이스, 베이스 클래스 또는 어노테이션에 대한 종속성이 없는 POJO입니다.
생성자 인자 확인
생성자 인자의 타입을 사용하여 생성자 인자 해석을 일치시킵니다. 빈 정의의 생성자 인수에 잠재적인 모호성이 존재하지 않는 경우, 빈 정의에서 생성자 인수가 정의되는 순서는 빈이 인스턴스화될 때 해당 인수가 적절한 생성자에게 제공되는 순서입니다. 다음 클래스를 생각해 보겠습니다:
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
ThingTwo와 ThingThree 클래스가 상속으로 관련되지 않는다고 가정하면 잠재적인 모호성이 존재하지 않습니다. 따라서 다음 구성은 정상적으로 작동하며<constructor-arg/> 요소에 생성자 인수 인덱스나 유형을 명시적으로 지정할 필요가 없습니다.
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
다른 빈이 참조되면 유형을 알 수 있으므로 앞의 예제에서와 같이 매칭이 발생할 수 있습니다.<value>true</value>와 같은 단순한 타입이 사용되는 경우 Spring은 값의 타입을 확인할 수 없으므로 도움 없이는 타입별로 일치시킬 수 없습니다. 다음 클래스를 고려해 보세요:
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private final int years;
// The Answer to Life, the Universe, and Everything
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
앞의 시나리오에서 컨테이너는 다음 예제와 같이 타입 속성을 사용하여 생성자 인수의 타입을 명시적으로 지정하면 단순 타입으로 타입 매칭을 사용할 수 있습니다:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
다음 예시와 같이 인덱스 속성을 사용하여 생성자 인수의 인덱스를 명시적으로 지정할 수 있습니다:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
인덱스를 지정하면 여러 단순 값의 모호성을 해결할 뿐만 아니라 생성자에 동일한 유형의 인수가 두 개 있는 경우 모호성을 해결할 수 있습니다.
인덱스는 0을 기반으로 합니다 |
다음 예제에서 볼 수 있듯이 생성자 매개변수 이름을 사용하여 값의 모호성을 해소할 수도 있습니다:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
이 기능을 바로 사용하려면 Spring이 생성자에서 매개변수 이름을 조회할 수 있도록 디버그 플래그를 활성화한 상태로 코드를 컴파일해야 합니다. 디버그 플래그를 사용하여 코드를 컴파일할 수 없거나 원하지 않는 경우@ConstructorPropertiesJDK 어노테이션을 사용하여 생성자 인수의 이름을 명시적으로 지정할 수 있습니다. 그러면 샘플 클래스는 다음과 같이 보일 것입니다:
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Setter-based Dependency Injection
세터 기반 DI는 인수가 없는 생성자 또는 인수가 없는 정적 팩토리 메서드를 호출하여 빈을 인스턴스화한 후 컨테이너가 빈의 세터 메서드를 호출하여 수행됩니다.
다음 예제는 순수 세터 주입을 사용해야만 종속성 주입이 가능한 클래스를 보여줍니다. 이 클래스는 기존 Java입니다. 컨테이너 특정 인터페이스, 베이스 클래스 또는 어노테이션에 대한 종속성이 없는 POJO입니다.
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
ApplicationContext는 관리하는 빈에 대해 생성자 기반 및 세터 기반 DI를 지원합니다. 또한 생성자 접근 방식을 통해 일부 종속성이 이미 주입된 후에도 세터 기반 DI를 지원합니다. 속성을 한 형식에서 다른 형식으로 변환하기 위해 PropertyEditor 인스턴스와 함께 사용하는 BeanDefinition의 형태로 종속성을 구성합니다. 그러나 대부분의 Spring 사용자는 이러한 클래스로 직접(즉, 프로그래밍 방식으로) 작업하지 않고 XML 빈정의, 주석이 달린 구성 요소(즉, @Component,@Controller 등으로 주석이 달린 클래스) 또는 Java 기반 @Configuration 클래스의 @Bean 메서드를 사용합니다. 이러한 소스는 내부적으로 BeanDefinition의 인스턴스로 변환되어 전체 Spring IoC 컨테이너 인스턴스를 로드하는 데 사용됩니다.
생성자 기반과 설정자 기반 DI를 혼합할 수 있으므로 필수 종속성에는 생성자를 사용하고 선택적 종속성에는 설정자 메서드 또는 구성 메서드를 사용하는 것이 좋은 경험 법칙입니다. 세터 메서드에 @Autowired주석을 사용하면 프로퍼티를 필수 종속성으로 만들 수 있지만 인수의 프로그래밍 방식 유효성 검사를 통해 생성자 주입을 사용하는 것이 더 바람직하다는 점에 유의하세요.
Spring 팀은 일반적으로 생성자 주입을 지지하는데, 이는 애플리케이션 구성 요소를 불변 객체로 구현할 수 있고 필수 종속성이 널이 되지 않도록 보장하기 때문입니다. 또한 생성자 주입된 컴포넌트는 항상 완전히 초기화된 상태로 클라이언트(호출) 코드에 반환됩니다. 참고로, 생성자 인수가 많으면 코드 냄새가 나기 때문에 클래스에 너무 많은 책임이 있을 수 있으므로 적절한 분리를 위해 리팩터링해야 합니다.
세터 주입은 주로 클래스 내에서 합리적인 기본값을 할당할 수 있는 선택적 종속성에만 사용해야 합니다. 그렇지 않으면 코드가 종속성을 사용하는 모든 곳에서 null이 아닌 검사를 수행해야 합니다. 세터 주입의 한 가지 장점은 세터 메서드를 사용하면 해당 클래스의 객체를 나중에 재구성하거나 다시 주입할 수 있다는 점입니다. 따라서 JMX MBeans를 통한 관리는 세터 인젝션의 강력한 사용 사례입니다.
특정 클래스에 가장 적합한 DI 스타일을 사용하세요. 때로는 소스가 없는 타사 클래스를 다룰 때 사용자가 직접 선택해야 하는 경우도 있습니다. 예를 들어 타사 클래스에 설정자 메서드가 노출되지 않는 경우 생성자 주입이 사용 가능한 유일한 DI 형태일 수 있습니다.
Dependency Resolution Process
컨테이너는 다음과 같이 빈 종속성 확인을 수행합니다:
- ApplicationContext가 생성되고 모든 빈을 설명하는 구성 메타데이터로 초기화됩니다. 구성 메타데이터는 XML, Java 코드 또는 어노테이션으로 지정할 수 있습니다.
- 각 빈에 대해 해당 종속성은 속성, 생성자 인수 또는 정적 팩토리 메서드(일반 생성자 대신 사용하는 경우)에 대한 인수의 형태로 표현됩니다. 이러한 종속성은 빈이 실제로 생성될 때 빈에 제공됩니다.
- 각 속성 또는 생성자 인수는 설정할 값의 실제 정의이거나 컨테이너의 다른 빈에 대한 참조입니다.
- 값인 각 속성 또는 생성자 인수는 지정된 형식에서 해당 속성 또는 생성자 인수의 실제 유형으로 변환됩니다. 기본적으로 Spring은 문자열 형식으로 제공된 값을 int,long, String, boolean 등과 같은 모든 기본 제공 유형으로 변환할 수 있습니다.
Spring 컨테이너는 컨테이너가 생성될 때 각 빈의 구성을 검증합니다. 그러나 빈 속성 자체는 빈이 실제로 생성될 때까지 설정되지 않습니다. 싱글톤 범위로 설정되고 사전 인스턴스화되도록 설정된 빈은 컨테이너가 생성될 때 생성됩니다(기본값). 범위는 Bean Scopes에서 정의됩니다. 그렇지 않으면 빈은 요청이 있을 때만 생성됩니다. 빈을 생성하면 빈의 종속성과 그 종속성의 종속성 등이 생성되고 할당되므로 빈의 그래프가 생성될 수 있습니다. 이러한 종속성 간의 해상도 불일치는 나중에, 즉 영향을 받는 빈을 처음 생성할 때 나타날 수 있다는 점에 유의하세요.
생성자 주입을 주로 사용하는 경우 해결할 수 없는 순환 종속성 시나리오가 생성될 수 있습니다.
예를 들어 클래스 A는 생성자 주입을 통해 클래스 B의 인스턴스를 필요로 하고, 클래스 B는 생성자 주입을 통해 클래스 A의 인스턴스를 필요로 합니다. 클래스 A와 B에 대한 빈이 서로 주입되도록 구성하면 Spring IoC 컨테이너는 런타임에 이 순환 참조를 감지하고BeanCurrentlyInCreationException을 던집니다.
한 가지 가능한 해결책은 일부 클래스의 소스 코드를 생성자가 아닌 설정자에 의해 구성되도록 편집하는 것입니다. 또는 생성자 주입을 피하고 설정자 주입만 사용하는 방법도 있습니다. 즉, 권장되지는 않지만 세터 주입으로 순환 종속성을 구성할 수 있습니다.
일반적인 경우(순환 종속성이 없는 경우)와 달리, 빈 A와 빈 B 사이의 순환 종속성은 빈 중 하나가 완전히 초기화되기 전에 다른 빈에 강제로 주입됩니다(고전적인 닭과 달걀 시나리오).
일반적으로 Spring이 올바른 작업을 수행한다고 믿을 수 있습니다. Spring은 컨테이너 로드 시 존재하지 않는 빈에 대한 참조 및 순환 종속성과 같은 구성 문제를 감지합니다. Spring은 빈이 실제로 생성될 때 가능한 한 늦게 프로퍼티를 설정하고 종속성을 해결합니다. 즉, 올바르게 로드된 Spring 컨테이너는 나중에 객체를 요청할 때 해당 객체 또는 해당 종속성 중 하나를 생성하는 데 문제가 있는 경우(예: 빈이 누락되거나 잘못된 속성으로 인해 예외를 던지는 경우) 예외를 생성할 수 있습니다. 일부 구성 문제에 대한 가시성이 지연될 수 있기 때문에 기본적으로 ApplicationContext 구현은 싱글톤 빈을 미리 인스턴스화합니다. 이러한 빈이 실제로 필요하기 전에 미리 생성하는 데 약간의 시간과 메모리가 소요되지만, 나중에가 아니라 ApplicationContext가 생성될 때 구성 문제를 발견할 수 있습니다. 이 기본 동작을 재정의하여 싱글톤 빈이 열심히 사전 인스턴스화되지 않고 느리게 초기화되도록 할 수 있습니다.
순환 종속성이 존재하지 않는 경우, 하나 이상의 협업 빈이 종속 빈에 주입될 때 각 협업 빈은 종속 빈에 주입되기 전에 완전히 구성됩니다. 즉, 빈 A에 빈 B에 대한 종속성이 있는 경우 Spring IoC 컨테이너는 빈 A에서 설정자 메서드를 호출하기 전에 빈 B를 완전히 구성합니다. 즉, 빈이 인스턴스화되고(사전 인스턴스화된 싱글톤이 아닌 경우), 종속성이 설정되고, 관련 수명 주기 메서드(예: 구성된 init 메서드 또는 InitializingBean 콜백 메서드)가 호출되는 것이죠.
Examples of Dependency Injection
다음 예제는 세터 기반 DI에 대한 XML 기반 구성 메타데이터를 사용합니다. Spring XML 구성 파일의 작은 부분은 다음과 같이 몇 가지 빈 정의를 지정합니다:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
다음 예제는 해당 ExampleBean 클래스를 보여줍니다:
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
앞의 예제에서는 XML 파일에 지정된 속성과 일치하도록 설정자가 선언되어 있습니다. 다음 예제에서는 생성자 기반 DI를 사용합니다:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested ref element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater ref attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
다음 예는 해당 ExampleBean 클래스를 보여줍니다:
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
빈 정의에 지정된 생성자 인수는 ExampleBean의 생성자 인자로 사용됩니다.
이제 이 예제의 변형으로, 생성자를 사용하는 대신 정적 팩토리 메서드를 호출하여 객체의 인스턴스를 반환하도록 Spring에 지시하는 경우를 생각해 보겠습니다:
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
다음 예제는 해당 ExampleBean 클래스를 보여줍니다:
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
정적 팩토리 메서드에 대한 인수는 실제로 생성자를 사용하는 것과 똑같이 <constructor-arg/> 요소로 제공됩니다. 팩토리 메서드가 반환하는 클래스의 유형은 정적 팩토리 메서드가 포함된 클래스와 동일한 유형일 필요는 없습니다(이 예에서는 동일하지만). 인스턴스(비정적) 팩토리 메서드는 본질적으로 동일한 방식으로 사용될 수 있으므로( 클래스 속성 대신 팩토리-빈 속성을 사용하는 것 외에는) 여기서는 이러한 세부 사항에 대해 설명하지 않습니다.
종속성 및 구성 상세 정보
이전 섹션에서 언급했듯이 빈 프로퍼티와 생성자 인수를 다른 관리되는 빈(공동 작업자)에 대한 참조로 정의하거나 인라인으로 정의된 값으로 정의할 수 있습니다. Spring의 XML 기반 구성 메타데이터는 이러한 목적을 위해 <property/> 및 <constructor-arg/> 요소 내에서 하위 요소 유형을 지원합니다.
스트레이트 값(프리미티브, 문자열 등)
<property/> 요소의 value 속성은 속성 또는 생성자 인수를 사람이 읽을 수 있는 문자열 표현으로 지정합니다. Spring의변환 서비스는 이러한 값을 문자열에서 속성 또는 인수의 실제 유형으로 변환하는 데 사용됩니다. 다음 예제에서는 다양한 값이 설정되는 것을 보여줍니다:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="misterkaoli"/>
</bean>
다음 예제에서는 더욱 간결한 XML 구성을 위해 p 네임스페이스를 사용합니다:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="misterkaoli"/>
</beans>
앞의 XML이 더 간결합니다. 그러나 빈 정의를 생성할 때 자동 속성 완성을 지원하는 IDE(예: IntelliJ IDEA 또는 Eclipse용 Spring 도구)를 사용하지 않는 한 설계 시점이 아닌 런타임에 오타가 발견됩니다. 이러한 IDE 지원을 적극 권장합니다.
다음과 같이 java.util.Properties 인스턴스를 구성할 수도 있습니다:
<bean id="mappings"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
Spring 컨테이너는 JavaBeans PropertyEditor 메커니즘을 사용하여 <value/> 요소 내부의 텍스트를java.util.Properties 인스턴스로 변환합니다. 이것은 좋은 지름길이며, Spring 팀에서 값 속성 스타일보다 중첩된 <value/> 요소의 사용을 선호하는 몇 안 되는 곳 중 하나입니다.
Idref 요소
Idref 요소는 컨테이너에 있는 다른 빈의 id (참조가 아닌 문자열 값)를 <constructor-arg/> 또는 <property/>요소에 전달하는 오류 방지 방법입니다. 다음 예제는 그 사용 방법을 보여줍니다:
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean"/>
</property>
</bean>
앞의 빈 정의 코드조각은 (런타임에) 다음 코드조각과 정확히 동일합니다:
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean"/>
</bean>
첫 번째 형태가 두 번째 형태보다 선호되는데, 그 이유는 idref 태그를 사용하면 컨테이너가 배포 시점에 참조된 이름이 지정된 빈이 실제로 존재하는지 확인할 수 있기 때문입니다. 두 번째 변형에서는 클라이언트 빈의 targetName 속성으로 전달되는 값에 대한 유효성 검사가 수행되지 않습니다. 클라이언트 빈이 실제로 인스턴스화될 때만 오타가 발견됩니다(치명적인 결과를 초래할 가능성이 높습니다). 클라이언트빈이 프로토타입 빈인 경우, 이 오타 및 그에 따른 예외는 컨테이너가 배포된 한참 후에야 발견될 수 있습니다.
Idref 요소의 로컬 속성은 더 이상 일반 빈 참조에 대한 값을 제공하지 않으므로 4.0 빈 XSD에서 더 이상 지원되지 않습니다. 4.0 스키마로 업그레이드할 때 기존 idref 로컬 참조를 idref 빈으로 변경하세요 |
<idref/> 요소가 가치를 제공하는 일반적인 위치(적어도 Spring 2.0 이전 버전에서는)는ProxyFactoryBean 빈 정의의 AOP 인터셉터 구성입니다. 인터셉터 이름을 지정할 때 <idref/> 요소를 사용하면 인터셉터 ID의 철자를 잘못 입력하는 것을 방지할 수 있습니다.
다른 빈에 대한 참조(공동 작업자)
참조 요소는 <constructor-arg/> 또는 <property/>정의 요소 내부의 마지막 요소입니다. 여기에서는 빈의 지정된 속성 값을 컨테이너에서 관리하는 다른 빈(공동 작업자)에 대한 참조로 설정합니다. 참조된 빈은 속성을 설정하려는 빈의 종속성이며, 속성이 설정되기 전에 필요에 따라 초기화됩니다. (공동 작업자가 싱글톤 빈인 경우 컨테이너에 의해 이미 초기화되어 있을 수 있습니다.) 모든 참조는 궁극적으로 다른 객체에 대한 참조입니다. 범위 지정 및 유효성 검사는 빈 또는 상위 속성을 통해 다른 객체의 ID 또는 이름을 지정하는지 여부에 따라 달라집니다.
<ref/> 태그의 빈 속성을 통해 대상 빈을 지정하는 것이 가장 일반적인 형태이며, 동일한 XML 파일에 있는지 여부에 관계없이 동일한 컨테이너 또는 상위 컨테이너에 있는 모든 빈에 대한 참조를 생성할 수 있습니다.빈 속성의 값은 대상 빈의 id 속성과 동일하거나 대상 빈의 이름 속성의 값 중 하나와 동일할 수 있습니다. 다음 예는 참조 요소를 사용하는 방법을 보여줍니다:
<ref bean="someBean"/>
부모 속성을 통해 대상 빈을 지정하면 현재 컨테이너의 부모 컨테이너에 있는 빈에 대한 참조가 생성됩니다. 부모속성의 값은 대상 빈의 id 속성 또는 대상 빈의 name 속성에 있는 값 중 하나와 동일할 수 있습니다. 대상 빈은 현재 컨테이너의 상위 컨테이너에 있어야 합니다. 이 빈 참조 변형은 주로 컨테이너 계층 구조가 있고 기존 빈을 부모 빈과 이름이 같은 프록시를 사용하여 부모 컨테이너에 래핑하려는 경우에 사용해야 합니다. 다음 목록은 부모 속성을 사용하는 방법을 보여줍니다:
<!-- in the parent context -->
<bean id="accountService" class="com.something.SimpleAccountService">
<!-- insert dependencies as required here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
</property>
<!-- insert other configuration and dependencies as required here -->
</bean>
Ref 요소의 로컬 속성은 더 이상 일반 빈 참조에 대한 값을 제공하지 않으므로 4.0 bean XSD에서 더 이상 지원되지 않습니다. 4.0 스키마로 업그레이드할 때 기존 참조 로컬 참조를 참조 빈으로 변경하세요 |
내부 빈
다음 예제에서 볼 수 있듯이 <property/> 또는 <constructor-arg/> 요소 내부의 <bean/> 요소는 내부 빈을 정의합니다:
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
내부 빈 정의에는 정의된 ID나 이름이 필요하지 않습니다. 지정된 경우 컨테이너는 이러한 값을 식별자로 사용하지 않습니다. 또한 내부 빈은 항상 익명이며 항상 외부 빈과 함께 생성되므로 컨테이너는 생성 시 범위 플래그를 무시합니다. 내부 빈에 독립적으로 액세스하거나 둘러싸는 빈이 아닌 다른 협업 빈에 주입하는 것은 불가능합니다.
코너 케이스로서, 예를 들어 싱글톤 빈 내에 포함된 요청 범위 내부 빈의 경우와 같이 사용자 정의 범위에서 파기 콜백을 수신할 수 있습니다. 내부 빈 인스턴스의 생성은 포함된 빈에 연결되지만, 파기 콜백을 통해 요청 범위의 라이프사이클에 참여할 수 있습니다. 이는 일반적인 시나리오는 아닙니다. 내부 빈은 일반적으로 단순히 포함 빈의 범위를 공유합니다.
컬렉션
<list/>, <set/>, <map/> 및 <props/> 요소는 각각 Java 컬렉션 유형 List, Set, Map 및 Properties의 속성 및 인수를 설정합니다. 다음 예는 이들 요소의 사용 방법을 보여줍니다:
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
맵 키 또는 값 또는 집합 값의 값은 다음 요소 중 어느 것이든 될 수 있습니다:
bean | ref | idref | list | set | map | props | value | null
컬렉션 병합
Spring 컨테이너는 컬렉션 병합도 지원합니다. 애플리케이션 개발자는 부모 <list/>, <map/>, <set/> 또는 <props/> 요소를 정의하고 자식 <list/>, <map/>, <set/> 또는 <props/> 요소가 부모 컬렉션의 값을 상속하고 재정의하도록 할 수 있습니다. 즉, 자식 컬렉션의 값은 부모 컬렉션과 자식 컬렉션의 요소를 병합한 결과이며, 자식 컬렉션 요소가 부모 컬렉션에 지정된 값을 재정의합니다.
병합에 대한 이 섹션에서는 부모-자식 빈 메커니즘에 대해 설명합니다. 부모 및 자식 빈 정의에 익숙하지 않은 독자는 계속하기 전에관련 섹션을 읽어보시기 바랍니다.
다음 예제에서는 컬렉션 병합을 보여줍니다:
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
자식 빈 정의의adminEmails 속성의 <props/> 요소에 merge=true 속성이 사용된 것을 볼 수 있습니다. 하위 빈이 컨테이너에 의해 확인되고 인스턴스화되면 결과 인스턴스에는 하위의adminEmails 컬렉션과 상위의 adminEmails 컬렉션을 병합한 결과가 포함된 adminEmails속성 컬렉션이 있습니다. 다음 목록은 결과를 보여줍니다:
administrator=administrator@example.com sales=sales@example.com support=support@example.co.uk
자식 속성 컬렉션의 값 집합은 부모 <props/>에서 모든 속성 요소를 상속하며, 지원 값에 대한 자식 값은 부모 컬렉션의 값을 재정의합니다.
이 병합 동작은 <list/>, <map/> 및 <set/>컬렉션 유형에도 유사하게 적용됩니다. <list/> 요소의 특정 경우에는 목록 컬렉션 유형과 관련된 의미론(즉, 값의 정렬된컬렉션 개념)이 유지됩니다. 부모 값은 모든 하위 목록의 값보다 우선합니다. 맵, 집합 및 속성 컬렉션 유형의 경우 순서가 존재하지 않습니다. 따라서 컨테이너가 내부적으로 사용하는 연관된 Map, Set 및 Properties 구현 유형의 기반이 되는 컬렉션 유형에는 순서 지정 의미가 적용되지 않습니다.
컬렉션 병합의 제한 사항
서로 다른 컬렉션 유형(예: 맵과 목록)은 병합할 수 없습니다. 병합을 시도하면 적절한 예외가 발생합니다. 병합 속성은 상속된 하위 하위 정의에 지정해야 합니다. 상위 컬렉션 정의에 병합 속성을 지정하는 것은 중복되며 원하는 병합이 이루어지지 않습니다.
강력하게 유형화된 컬렉션
Java의 일반 유형 지원 덕분에 강력하게 유형화된 컬렉션을 사용할 수 있습니다. 즉, (예를 들어) String 요소만 포함할 수 있도록 Collection 유형을 선언할 수 있습니다. Spring을 사용하여 강력한 타입의 컬렉션을 빈에 종속적으로 주입하는 경우, 강력한 타입의 컬렉션인스턴스의 요소가 컬렉션에 추가되기 전에 적절한 타입으로 변환되도록 Spring의 타입 변환 지원을 활용할 수 있습니다. 다음 Java 클래스 및 빈 정의는 이를 수행하는 방법을 보여줍니다:
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="something" class="x.y.SomeClass">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
</beans>
무언가 빈의 계정 속성이 주입될 준비가 되면, 강력하게 유형화된 Map<String, Float>의 요소 유형에 대한 제네릭 정보를 리플렉션을 통해 사용할 수 있습니다. 따라서 Spring의 유형 변환 인프라는 다양한 값 요소를 Float 유형으로 인식하고 문자열 값(9.99, 2.75 및3.99)을 실제 Float 유형으로 변환합니다.
Null 및 빈 문자열 값
Spring은 속성 등에 대한 빈 인수를 빈 문자열로 취급합니다. 다음 XML 기반 구성 메타데이터 스니펫은 이메일 속성을 빈문자열 값("")으로 설정합니다.
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
앞의 예는 다음 Java 코드와 동일합니다:
exampleBean.setEmail("");
<null/> 요소는 null 값을 처리합니다. 다음 목록은 그 예시를 보여줍니다:
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
앞의 구성은 다음 Java 코드와 동일합니다:
exampleBean.setEmail(null);
P 네임스페이스가 있는 XML 바로 가기
P 네임스페이스를 사용하면 중첩된<property/> 요소 대신 빈 요소의 속성을 사용하여 속성 값을 공동 작업하는 빈 또는 둘 다를 설명할 수 있습니다.
Spring은 XML 스키마 정의를 기반으로 하는 네임스페이스와 함께 확장 가능한 구성 형식을 지원합니다. 이 장에서 설명하는 빈 구성 형식은 XML 스키마 문서에 정의되어 있습니다. 그러나 p-네임스페이스는 XSD 파일에 정의되어 있지 않으며 Spring의 코어에만 존재합니다.
다음 예제에서는 동일한 결과로 해석되는 두 개의 XML 스니펫(첫 번째는 표준 XML 형식을 사용하고 두 번째는 p-네임스페이스를 사용)을 보여 줍니다:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="someone@somewhere.com"/>
</bean>
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="someone@somewhere.com"/>
</beans>
이 예는 빈 정의에서 이메일이라는 p-namespace의 속성을 보여줍니다. 이것은 Spring이 속성 선언을 포함하도록 지시합니다. 앞서 언급했듯이 p 네임스페이스에는 스키마 정의가 없으므로 속성 이름을 속성 이름으로 설정할 수 있습니다.
이 다음 예제에는 다른 빈에 대한 참조가 있는 두 개의 빈 정의가 더 포함되어 있습니다:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
</beans>
이 예제에는 p 네임스페이스를 사용하는 속성 값뿐만 아니라 특수 형식을 사용하여 속성 참조를 선언하는 것도 포함되어 있습니다. 첫 번째 빈 정의에서는 <property name="spouse" ref="jane"/>을 사용하여 빈john에서 빈 jane으로 참조를 생성하는 반면, 두 번째 빈 정의에서는 p:spouse-ref="jane을 속성으로 사용하여 정확히 동일한 작업을 수행합니다. 이 경우 spouse는 속성 이름이고, -ref 부분은 이것이 직선 값이 아니라 다른 빈에 대한 참조임을 나타냅니다.
P 네임스페이스는 표준 XML 형식만큼 유연하지 않습니다. 예를 들어, 속성 참조를 선언하는 형식은 Ref로 끝나는 속성과 충돌하지만 표준 XML 형식은 충돌하지 않습니다. 세 가지 접근 방식을 동시에 사용하는 XML 문서를 만들지 않도록 접근 방식을 신중하게 선택하고 팀원들에게 이를 알리는 것이 좋습니다 |
C 네임스페이스를 사용한 XML 바로 가기
Spring 3.1에 도입된 c-네임스페이스는 p-네임스페이스의 XML 바로 가기와 유사하게 중첩된 생성자-arg 요소가 아닌 생성자 인수를 구성하기 위한 인라인 어트리뷰트를 허용합니다.
다음 예제에서는 c: 네임스페이스를 사용하여 생성자기반 종속성 주입과 동일한 작업을 수행합니다:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- traditional declaration with optional argument names -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="something@somewhere.com"/>
</bean>
<!-- c-namespace declaration with argument names -->
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>
</beans>
C: 네임스페이스는 생성자 인수를 이름으로 설정하기 위해 p: one(빈 참조의 경우 후행 -ref )과 동일한 규칙을 사용합니다. 마찬가지로, XSD 스키마에 정의되어 있지 않더라도 XML 파일에 선언해야 합니다(Spring 코어 내부에 존재).
생성자 인자 이름을 사용할 수 없는 드문 경우(일반적으로 디버깅 정보 없이 바이트코드가 컴파일된 경우)에는 다음과 같이 인자 인덱스에 대한 폴백을 사용할 수 있습니다:
<!-- c-namespace index declaration -->
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
c:_2="something@somewhere.com"/>
XML 문법으로 인해 인덱스 표기법에는 선행 _가 있어야 하는데, 이는 XML 속성 이름이 숫자로 시작할 수 없기 때문입니다(일부 IDE에서는 허용하지만). <constructor-arg> 요소에도 해당 인덱스 표기법을 사용할 수 있지만 일반적으로 일반 선언 순서로 충분하기 때문에 일반적으로 사용되지는 않습니다 |
실제로는 생성자 확인메커니즘이 인수를 일치시키는 데 매우 효율적이므로 꼭 필요한 경우가 아니라면 구성 전체에서 이름 표기법을 사용하는 것이 좋습니다.
복합 프로퍼티 이름
최종 속성 이름을 제외한 경로의 모든 구성 요소가 null이 아닌 한, 빈 속성을 설정할 때 복합 또는 중첩 속성 이름을 사용할 수 있습니다. 다음 빈 정의를 고려해 보세요:
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
Something 빈에는 fred 속성이 있고, 그 속성에 bob 속성이 있으며, 그 속성에 새미속성이 있고, 최종 새미 속성이 123 값으로 설정되고 있습니다. 이것이 작동하려면 빈이 생성된 후 무언가의 프레드 프로퍼티와 프레드의 밥 프로퍼티가 널이 아니어야 합니다. 그렇지 않으면 NullPointerException이 발생합니다.
의존성 사용
한 빈이 다른 빈의 종속성이라는 것은 일반적으로 한 빈이 다른 빈의 속성으로 설정되어 있다는 것을 의미합니다. 일반적으로 XML 기반 구성 메타데이터의 <ref/>요소를 사용하여 이를 수행합니다. 그러나 때로는 빈 간의 종속성이 직접적이지 않을 수도 있습니다. 예를 들어 데이터베이스 드라이버 등록과 같이 클래스의 정적 초기화기가 트리거되어야 하는 경우를 들 수 있습니다. Depends-on 속성은 이 요소를 사용하는 빈이 초기화되기 전에 하나 이상의 빈이 초기화되도록 명시적으로 강제할 수 있습니다. 다음 예에서는 depends-on 속성을 사용하여 단일 빈에 대한 종속성을 표현합니다:
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
여러 빈에 대한 종속성을 표현하려면 depends-on 속성의 값으로 빈 이름 목록을 제공합니다(쉼표, 공백 및 세미콜론이 유효한 구분 기호입니다):
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
Depends-on 속성은 초기화 시간 종속성과 싱글톤 빈의 경우에만 해당되는 소멸 시간 종속성을 모두 지정할 수 있습니다. 지정된 빈과의 의존 관계를 정의하는 종속 빈은 지정된 빈 자체가 소멸되기 전에 먼저 소멸됩니다. 따라서 의존은 종료 순서도 제어할 수 있습니다 |
지연 초기화된 빈
기본적으로 애플리케이션 컨텍스트 구현은 초기화 프로세스의 일부로 모든싱글톤 빈을 열심히 생성하고 구성합니다. 일반적으로 이러한 사전 초기화는 구성이나 주변 환경의 오류가 몇 시간 또는 며칠 후에 발견되는 것이 아니라 즉시 발견되므로 바람직합니다. 이러한 동작이 바람직하지 않은 경우, 빈 정의를 지연 초기화됨으로 표시하여 싱글톤 빈의 사전 인스턴스화를 방지할 수 있습니다. 지연 초기화된 빈은 시작 시점이 아니라 처음 요청될 때 빈 인스턴스를 생성하도록 IoC 컨테이너에 지시합니다.
XML에서 이 동작은 다음 예제에서 볼 수 있듯이 <bean/>요소의 lazy-init 속성에 의해 제어됩니다:
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
앞의 구성이 애플리케이션 컨텍스트에 의해 사용되는 경우, 애플리케이션 컨텍스트가 시작될 때 lazy 빈은 열심히 사전 인스턴스화되지 않는 반면, not.lazy 빈은 열심히 사전 인스턴스화됩니다.
그러나 지연 초기화된 빈이 지연 초기화되지 않은 싱글톤 빈의 종속성인 경우, 싱글톤의 종속성을 충족해야 하기 때문에 ApplicationContext는 시작 시 지연 초기화된 빈을 생성합니다. 지연 초기화된 빈은 지연 초기화되지 않은 다른 곳의 싱글톤 빈에 주입됩니다.
다음 예제에서 볼 수 있듯이 <beans/> 요소의default-lazy-init 속성을 사용하여 컨테이너 수준에서 지연 초기화를 제어할 수도 있습니다:
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
Autowiring Collaborators
Spring 컨테이너는 협업하는 빈 간의 관계를 자동 와이어링할 수 있습니다. 애플리케이션 컨텍스트의 내용을 검사하여 Spring이 사용자의 빈에 대해 공동 작업자(다른 빈)를 자동으로 확인하도록 할 수 있습니다. 자동 와이어링에는 다음과 같은 이점이 있습니다:
- 자동 배선을 사용하면 속성이나 생성자 인수를 지정할 필요성을 크게 줄일 수 있습니다. (이 장의 다른 곳에서 설명하는 빈 템플릿과 같은 다른 메커니즘도 이와 관련하여 유용합니다.)
- 자동 배선은 객체가 진화함에 따라 구성을 업데이트할 수 있습니다. 예를 들어 클래스에 종속성을 추가해야 하는 경우 구성을 수정할 필요 없이 해당 종속성을 자동으로 충족시킬 수 있습니다. 따라서 자동 배선은 개발 중에 특히 유용할 수 있으며, 코드 기반이 더 안정화되면 명시적 배선으로 전환하는 옵션을 부정하지 않습니다.
XML 기반 구성 메타데이터(종속성 주입 참조)를 사용하는 경우<bean/> 요소의 자동 와이어 속성을 사용하여 빈 정의에 대한 자동 와이어 모드를 지정할 수 있습니다. 자동 와이어링 기능에는 네 가지 모드가 있습니다. 빈별로 자동 와이어링을 지정하여 어떤 빈을 자동 와이어링할지 선택할 수 있습니다. 다음 표에서는 네 가지 자동 와이어링 모드에 대해 설명합니다:
아니요 | (기본값) 자동 배선 없음. 빈 참조는 참조 요소로 정의해야 합니다. 공동 작업자를 명시적으로 지정하면 제어 및 명확성이 향상되므로 대규모 배포의 경우 기본 설정을 변경하는 것은 권장되지 않습니다. 어느 정도는 시스템의 구조를 문서화합니다. |
byName | 속성 이름으로 자동 배선. Spring은 자동 배선해야 하는 프로퍼티와 이름이 같은 빈을 찾습니다. 예를 들어, 빈 정의가 이름으로 자동 배선하도록 설정되어 있고 마스터 속성을 포함하는 경우(즉, setMaster(..) 메서드가 있는 경우) Spring은 마스터라는 이름의 빈 정의를 찾아서 이를 사용하여 속성을 설정합니다. |
byType | 컨테이너에 해당 속성 유형의 빈이 정확히 하나만 존재하는 경우 속성을 자동 연결합니다. 두 개 이상 존재하면 치명적인 예외가 발생하며, 이는 해당 빈에 대해 byType 자동 배선을 사용할 수 없음을 나타냅니다. 일치하는 빈이 없으면 아무 일도 일어나지 않습니다(프로퍼티가 설정되지 않음). |
생성자 | ByType과 유사하지만 생성자 인수에 적용됩니다. 컨테이너에 생성자 인자 유형의 빈이 정확히 하나도 없으면 치명적인 에러가 발생합니다. |
ByType 또는 생성자 자동 배선 모드를 사용하면 배열과 타입 컬렉션을 배선할 수 있습니다. 이러한 경우 예상 유형과 일치하는 컨테이너 내의 모든 자동 와이어 후보가 종속성을 충족하기 위해 제공됩니다. 예상 키 유형이 문자열인 경우 강력하게 유형화된 Map 인스턴스를 자동 와이어링할 수 있습니다. 자동 와이어링된 Map인스턴스의 값은 예상 유형과 일치하는 모든 빈 인스턴스로 구성되며,Map 인스턴스의 키에는 해당 빈 이름이 포함됩니다.
Limitations and Disadvantages of Autowiring
Autowiring works best when it is used consistently across a project. If autowiring is not used in general, it might be confusing to developers to use it to wire only one or two bean definitions.
Consider the limitations and disadvantages of autowiring:
- Explicit dependencies in property and constructor-arg settings always override autowiring. You cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). This limitation is by-design.
- Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is careful to avoid guessing in case of ambiguity that might have unexpected results. The relationships between your Spring-managed objects are no longer documented explicitly.
- Wiring information may not be available to tools that may generate documentation from a Spring container.
- Multiple bean definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or Map instances, this is not necessarily a problem. However, for dependencies that expect a single value, this ambiguity is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
In the latter scenario, you have several options:
- Abandon autowiring in favor of explicit wiring.
- Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as described in the next section.
- Designate a single bean definition as the primary candidate by setting the primary attribute of its <bean/> element to true.
- Implement the more fine-grained control available with annotation-based configuration, as described in Annotation-based Container Configuration.
Excluding a Bean from Autowiring
빈 단위로 자동 와이어링에서 빈을 제외할 수 있습니다. Spring의 XML 형식에서 <bean/> 요소의 autowire-candidate 속성을 false로 설정합니다. 컨테이너는 해당 특정 빈 정의를 자동 와이어링 인프라에서 사용할 수 없게 만듭니다( @Autowired와같은 어노테이션 스타일 구성 포함).
자동 와이어 후보 속성은 유형 기반 자동 와이어링에만 영향을 주도록 설계되었습니다. 지정된 빈이 자동 와이어 후보로 표시되지 않은 경우에도 해결되는 이름에 의한 명시적 참조에는 영향을 주지 않습니다. 따라서 이름별 자동 와이어링은 이름이 일치하는 경우 빈을 주입합니다 |
빈 이름에 대한 패턴 매칭을 기반으로 자동 와이어 후보를 제한할 수도 있습니다. 최상위 <beans/> 요소는기본 자동 와이어 후보 속성 내에서 하나 이상의 패턴을 허용합니다. 예를 들어, 자동 와이어 후보 상태를 이름이 Repository로 끝나는 모든 빈으로 제한하려면 *Repository 값을 제공합니다. 여러 패턴을 제공하려면 쉼표로 구분된 목록으로 정의하세요. 빈 정의의 자동 와이어 후보 속성에 대해참 또는 거짓의 명시적 값이 항상 우선합니다. 이러한 빈의 경우 패턴 일치 규칙이 적용되지 않습니다.
이러한 기술은 자동 와이어링으로 다른 빈에 주입하지 않으려는 빈에 유용합니다. 자동 배선을 사용하여 제외된 빈 자체를 구성할 수 없다는 의미는 아닙니다. 오히려 해당 빈 자체는 다른 빈을 자동 배선할 수 있는 후보가 아닙니다.
Method Injection
대부분의 애플리케이션 시나리오에서 컨테이너의 대부분의 빈은싱글톤입니다. 싱글톤 빈이 다른 싱글톤 빈과 협업해야 하거나 싱글톤이 아닌 빈이 다른 비싱글톤 빈과 협업해야 하는 경우, 일반적으로 한 빈을 다른 빈의 속성으로 정의하여 종속성을 처리합니다. 문제는 빈의 라이프사이클이 다를 때 발생합니다. 싱글톤 빈 A가 싱글톤이 아닌(프로토타입) 빈 B를 사용해야 한다고 가정해 보겠습니다. 컨테이너는 싱글톤 빈 A를 한 번만 생성하므로 속성을 설정할 수 있는 기회가 한 번만 주어집니다. 컨테이너는 필요할 때마다 빈 A에 빈 B의 새 인스턴스를 제공할 수 없습니다.
해결책은 제어의 반전을 포기하는 것입니다. 애플리케이션 컨텍스트 인식 인터페이스를 구현하고 컨테이너에 대한 getBean("B") 호출이 빈 A가 필요할 때마다 (일반적으로 새로운) 빈 B 인스턴스를 요청하도록 함으로써 빈 A가 컨테이너를 인식하도록 만들수 있습니다. 다음 예제는 이 접근 방식을 보여줍니다:
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* A class that uses a stateful Command-style class to perform
* some processing.
*/
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
앞의 방법은 비즈니스 코드가 Spring 프레임워크를 인식하고 결합되어 있기 때문에 바람직하지 않습니다. Spring IoC 컨테이너의 다소 고급 기능인 메서드 주입을 사용하면 이 사용 사례를 깔끔하게 처리할 수 있습니다.
메서드 주입의 동기에 대한 자세한 내용은이 블로그 항목에서 확인할 수 있습니다.
Lookup Method Injection
조회 메서드 주입은 컨테이너가 컨테이너 관리 빈의 메서드를 재정의하고 컨테이너의 다른 명명된 빈에 대한 조회 결과를 반환하는 컨테이너의 기능입니다. 조회에는 일반적으로 이전 섹션에서 설명한 시나리오에서와 같이 프로토타입 빈이 포함됩니다. Spring 프레임워크는 CGLIB 라이브러리에서 바이트코드 생성을 사용하여 메서드를 재정의하는 서브클래스를 동적으로 생성함으로써 이 메서드 주입을 구현합니다.
|
이전 코드 스니펫의 CommandManager 클래스의 경우 Spring 컨테이너는 createCommand()메서드의 구현을 동적으로 재정의합니다. 재작업된 예제에서 볼 수 있듯이 CommandManager 클래스에는 Spring 종속성이 없습니다:
package fiona.apple;
// no more Spring imports!
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}
주입할 메서드가 포함된 클라이언트 클래스(이 경우 CommandManager )에서 주입할 메서드에는 다음 형식의 서명이 필요합니다:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
메서드가 추상적인 경우 동적으로 생성된 하위 클래스가 메서드를 구현합니다. 그렇지 않으면 동적으로 생성된 하위 클래스가 원래 클래스에 정의된 구체적인 메서드를 재정의합니다. 다음 예제를 살펴보겠습니다:
<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
<!-- inject dependencies here as required -->
</bean>
<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="myCommand"/>
</bean>
CommandManager로 식별된 빈은 myCommand 빈의 새 인스턴스가 필요할 때마다 자체 createCommand() 메서드를 호출합니다. 실제로 필요한 경우 myCommand 빈을 프로토타입으로 배포하는 데 주의해야 합니다. 싱글톤인 경우 매번 동일한 myCommand빈 인스턴스가 반환됩니다.
또는 다음 예제에서 볼 수 있듯이 어노테이션 기반 컴포넌트 모델 내에서 @Lookup 어노테이션을 통해 조회 메서드를 선언할 수 있습니다:
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand();
}
또는 보다 관용적으로, 대상 빈이 선언된 조회 메서드의 반환 유형에 대해 확인되는 것에 의존할 수 있습니다:
public abstract class CommandManager {
public Object process(Object commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract Command createCommand();
}
추상 클래스가 기본적으로 무시되는 Spring의 구성 요소 검색 규칙과 호환되도록 하려면 일반적으로 이러한 주석이 달린 조회 메서드를 구체적인 스텁 구현으로 선언해야 합니다. 이 제한은 명시적으로 등록되거나 명시적으로 가져온 빈 클래스에는 적용되지 않습니다.
범위가 다른 대상 빈에 액세스하는 또 다른 방법은 ObjectFactory/Provider 주입 지점입니다. 범위가 지정된 빈을 종속성으로 참조하세요.
ServiceLocatorFactoryBean (org.springframework.beans.factory.config 패키지에 있음)도 유용할 수 있습니다.
|
Arbitrary Method Replacement
조회 메서드 주입보다 덜 유용한 메서드 주입 형태는 관리되는 빈의 임의 메서드를 다른 메서드 구현으로 대체할 수 있는 기능입니다. 이 기능이 실제로 필요할 때까지 이 섹션의 나머지 부분은 건너뛰셔도 됩니다.
XML 기반 구성 메타데이터를 사용하면 대체 메서드 요소를 사용하여 배포된 빈에 대해 기존 메서드 구현을 다른 메서드 구현으로 대체할 수 있습니다. 재정의하려는 computeValue라는 메서드가 있는 다음 클래스를 생각해 보겠습니다:
public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
// some other methods...
}
다음 예제에서 볼 수 있듯이 org.springframework.beans.factory.support.MethodReplacer인터페이스를 구현하는 클래스는 새로운 메서드 정의를 제공합니다:
/**
* meant to be used to override the existing computeValue(String)
* implementation in MyValueCalculator
*/
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
// get the input value, work with it, and return a computed result
String input = (String) args[0];
...
return ...;
}
}
원래 클래스를 배포하고 메서드 오버라이드를 지정하는 빈 정의는 다음 예제와 유사합니다:
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
<!-- arbitrary method replacement -->
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
재정의되는 메서드의 메서드 서명을 나타내기 위해 <replaced-method/>요소 내에 하나 이상의 <arg-type/> 요소를 사용할 수 있습니다. 인수의 서명은 메서드가 오버로드되고 클래스 내에 여러 변형이 존재하는 경우에만 필요합니다. 편의를 위해 인수의 타입 문자열은 정규화된 타입 이름의 하위 문자열일 수 있습니다. 예를 들어 다음은 모두java.lang.String과 일치합니다:
java.lang.String
String
Str
인수의 수는 가능한 각 선택을 구분하기에 충분한 경우가 많으므로 이 바로 가기를 사용하면 인수 유형과 일치하는 가장 짧은 문자열만 입력할 수 있으므로 많은 타이핑을 절약할 수 있습니다.
Bean Scopes
빈 정의를 생성하면 해당 빈 정의에 정의된 클래스의 실제 인스턴스를 생성하기 위한 레시피가 생성됩니다. 빈 정의가 레시피라는 개념이 중요한 이유는 클래스와 마찬가지로 하나의 레시피에서 많은 객체 인스턴스를 생성할 수 있기 때문입니다.
특정 빈 정의에서 생성되는 객체에 연결될 다양한 종속성과 구성 값을 제어할 수 있을 뿐만 아니라 특정 빈 정의에서 생성되는 객체의 범위도 제어할 수 있습니다. 이 접근 방식은 Java 클래스 수준에서 객체의 범위를 베이크할 필요 없이 구성을 통해 생성하는 객체의 범위를 선택할 수 있기 때문에 강력하고 유연합니다. 빈은 여러 범위 중 하나에 배포되도록 정의할 수 있습니다. Spring 프레임워크는 6개의 범위를 지원하며, 이 중 4개의 범위는 웹 인식 ApplicationContext를 사용하는 경우에만 사용할 수 있습니다.사용자 정의 스코프를 생성할 수도 있습니다.
다음 표에서는 지원되는 스코프에 대해 설명합니다:
싱글톤 | (기본값) 단일 빈 정의의 범위를 각 Spring IoC 컨테이너에 대한 단일 객체 인스턴스로 제한합니다. |
프로토타입 | 단일 빈 정의의 범위를 원하는 수의 객체 인스턴스로 지정합니다. |
request | 단일 빈 정의의 범위를 단일 HTTP 요청의 라이프사이클로 지정합니다. 즉, 각 HTTP 요청에는 단일 빈 정의에 기반하여 생성된 자체 빈 인스턴스가 있습니다. 웹 인식 Spring ApplicationContext의 컨텍스트에서만 유효합니다. |
session | 단일 빈 정의의 범위를 HTTP 세션의 라이프사이클로 한정합니다. 웹 인식 스프링 애플리케이션 컨텍스트의 컨텍스트에서만 유효합니다. |
application | 단일 빈 정의의 범위를 서블릿 컨텍스트의 라이프사이클로 제한합니다. 웹 인식 스프링 애플리케이션 컨텍스트의 컨텍스트에서만 유효합니다. |
websocket | 단일 빈 정의를 웹소켓의 라이프사이클로 범위를 지정합니다. 웹 인식 스프링 애플리케이션 컨텍스트의 컨텍스트에서만 유효합니다. |
스레드 범위를 사용할 수 있지만 기본적으로 등록되지 않습니다. 자세한 내용은SimpleThreadScope 문서를 참조하세요. 이 스코프 또는 다른 사용자 정의 스코프를 등록하는 방법에 대한 지침은사용자 정의 스코프 사용을 참조하세요 |
The Singleton Scope
싱글톤 빈의 공유 인스턴스는 하나만 관리되며, 해당 빈 정의와 일치하는 ID를 가진 빈에 대한 모든 요청은 해당 특정 빈 인스턴스 하나를 Spring 컨테이너에서 반환하게 됩니다.
다시 말해, 빈 정의를 정의하고 해당 정의가 싱글톤으로 범위가 지정되면 Spring IoC 컨테이너는 해당 빈 정의에 의해 정의된 객체의 인스턴스를 정확히 하나만 생성합니다. 이 단일 인스턴스는 이러한 싱글톤 빈의 캐시에 저장되며, 해당 명명된 빈에 대한 모든 후속 요청 및 참조는 캐시된 객체를 반환합니다. 다음 이미지는 싱글톤 범위의 작동 방식을 보여줍니다:
Spring의 싱글톤 빈 개념은 GoF(Gang of Four) 패턴 책에 정의된 싱글톤 패턴과 다릅니다. GoF 싱글톤은 특정 클래스의 인스턴스가 클래스 로더당 하나만 생성되도록 객체의 범위를 하드코딩합니다. Spring 싱글톤의 범위는 컨테이너별 및 빈별로 설명하는 것이 가장 좋습니다. 즉, 단일 Spring 컨테이너에서 특정 클래스에 대해 하나의 빈을 정의하면 Spring 컨테이너는 해당 빈 정의에 의해 정의된 클래스의 인스턴스를 하나만 생성합니다. 싱글톤 범위는 Spring의 기본 범위입니다. XML에서 빈을 싱글톤으로 정의하려면 다음 예제와 같이 빈을 정의할 수 있습니다:
<bean id="accountService" class="com.something.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
The Prototype Scope
싱글톤이 아닌 프로토타입 범위의 빈 배포는 특정 빈에 대한 요청이 있을 때마다 새로운 빈 인스턴스를 생성합니다. 즉, 빈이 다른 빈에 주입되거나 컨테이너에서 getBean() 메서드 호출을 통해 요청됩니다. 원칙적으로 모든 상태 저장 빈에는 프로토타입 스코프를 사용하고 상태 비저장 빈에는 싱글톤 스코프를 사용해야 합니다.
다음 다이어그램은 Spring 프로토타입 스코프를 보여줍니다:
(일반적인 DAO(데이터 액세스 객체)는 대화 상태를 보유하지 않기 때문에 일반적으로 프로토타입으로 구성되지 않습니다. 싱글톤 다이어그램의 핵심을 재사용하는 것이 더 쉬웠기 때문입니다)
다음 예제는 XML에서 빈을 프로토타입으로 정의합니다:
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
다른 범위와 달리 Spring은 프로토타입 빈의 전체 라이프사이클을 관리하지 않습니다. 컨테이너는 프로토타입 객체를 인스턴스화, 구성 및 기타 방식으로 어셈블하여 클라이언트에 전달하며, 해당 프로토타입 인스턴스에 대한 추가 기록은 남기지 않습니다. 따라서 초기화 수명 주기 콜백 메서드는 범위에 관계없이 모든 객체에서 호출되지만, 프로토타입의 경우 구성된 소멸 수명 주기 콜백은 호출되지 않습니다. 클라이언트 코드는 프로토타입 범위의 객체를 정리하고 프로토타입 빈이 보유하고 있는 값비싼 리소스를 해제해야 합니다. Spring 컨테이너가 프로토타입 범위의 빈이 보유한 리소스를 해제하도록 하려면 정리해야 하는 빈에 대한 참조가 있는 사용자 정의 빈 포스트 프로세서를사용해보십시오.
어떤 측면에서, 프로토타입 범위의 빈과 관련된 Spring 컨테이너의 역할은 Java 새 연산자를 대체하는 것입니다. 그 이후의 모든 라이프사이클 관리는 클라이언트에서 처리해야 합니다. (Spring 컨테이너에서 빈의 라이프사이클에 대한 자세한 내용은 라이프사이클 콜백을 참조하세요.)
Singleton Beans with Prototype-bean Dependencies
프로토타입 빈에 대한 종속성이 있는 싱글톤 범위 빈을 사용하는 경우, 종속성은 인스턴스화 시점에 해결된다는 점에 유의하세요. 따라서 프로토타입 범위 빈을 싱글톤 범위 빈에 종속성 주입하는 경우 새 프로토타입 빈이 인스턴스화된 다음 싱글톤 빈에 종속성 주입됩니다. 프로토타입 인스턴스는 싱글톤 범위 빈에 제공되는 유일한 인스턴스입니다.
그러나 싱글톤 범위 빈이 런타임에 프로토타입 범위 빈의 새 인스턴스를 반복적으로 획득하기를 원한다고 가정해 보겠습니다. 스프링 컨테이너가 싱글톤 빈을 인스턴스화하고 해당 종속성을 해결하고 주입할 때 한 번만 발생하므로 프로토타입 범위의 빈을 싱글톤 빈에 종속성 주입할 수 없습니다. 런타임에 프로토타입 빈의 새 인스턴스가 두 번 이상 필요한 경우 메서드 주입을 참조하세요.
Request, Session, Application, and WebSocket Scopes
요청, 세션, 애플리케이션 및 웹소켓 범위는 웹 인식 스프링 애플리케이션 컨텍스트 구현(예:XmlWebApplicationContext)을 사용하는 경우에만 사용할 수 있습니다. 이러한 범위를 ClassPathXmlApplicationContext와 같은 일반 Spring IoC 컨테이너와 함께 사용하는 경우 알 수 없는 빈 범위에 대해 불만을 제기하는 IllegalStateException이 throw됩니다.
초기 웹 구성
요청, 세션, 애플리케이션 및웹소켓 수준(웹 범위 지정 빈)에서 빈의 범위 지정을 지원하려면 빈을 정의하기 전에 몇 가지 사소한 초기 구성이 필요합니다. (이 초기 설정은 표준 범위인 싱글톤과 프로토타입에는 필요하지 않습니다.)
이 초기 설정을 수행하는 방법은 특정 서블릿 환경에 따라 다릅니다.
Spring Web MVC 내에서 범위가 지정된 빈에 액세스하는 경우, 사실상 Spring DispatcherServlet에 의해 처리되는 요청 내에서, 특별한 설정이 필요하지 않습니다.DispatcherServlet은 이미 모든 관련 상태를 노출하고 있습니다.
JSF를 사용하는 경우와 같이 Spring의DispatcherServlet 외부에서 처리되는 요청이 있는 서블릿 웹 컨테이너를 사용하는 경우,org.springframework.web.context.request.RequestContextListener ServletRequestListener를 등록해야 합니다. 이는 WebApplicationInitializer 인터페이스를 사용하여 프로그래밍 방식으로 수행할 수 있습니다. 또는 웹 애플리케이션의 web.xml 파일에 다음 선언을 추가할 수 있습니다:
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
또는 수신기 설정에 문제가 있는 경우 Spring의RequestContextFilter를 사용하는 것도 고려해 보세요. 필터 매핑은 주변 웹 애플리케이션 구성에 따라 달라지므로 적절하게 변경해야 합니다. 다음 목록은 웹 애플리케이션의 필터 부분을 보여줍니다:
<web-app>
...
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
DispatcherServlet, RequestContextListener, RequestContextFilter는 모두 정확히 동일한 작업을 수행합니다. 즉, HTTP 요청 객체를 해당 요청을 서비스하는 스레드에 바인딩하는 것입니다. 이렇게 하면 요청 및 세션 범위가 지정된 빈을 호출 체인의 더 아래에서 사용할 수 있습니다.
요청 범위
빈 정의에 대한 다음 XML 구성을 고려해 보세요:
<bean id="loginAction" class="com.something.LoginAction" scope="request"/>
Spring 컨테이너는 각각의 모든 HTTP 요청에 대해loginAction 빈 정의를 사용하여 LoginAction 빈의 새 인스턴스를 생성합니다. 즉,loginAction 빈은 HTTP 요청 수준에서 범위가 지정됩니다. 생성된 인스턴스의 내부 상태는 원하는 만큼 변경할 수 있습니다. 동일한 loginAction 빈 정의에서 생성된 다른 인스턴스에는 이러한 상태 변경이 표시되지 않으므로 개별 요청에만 해당됩니다. 요청이 처리를 완료하면 해당 요청으로 범위가 지정된 빈은 삭제됩니다.
어노테이션 기반 컴포넌트 또는 Java 구성을 사용하는 경우 @RequestScope 어노테이션을 사용하여 요청 범위에 컴포넌트를 할당할 수 있습니다. 다음 예제는 그 방법을 보여줍니다:
@RequestScope
@Component
public class LoginAction {
// ...
}
세션 범위
빈 정의에 대한 다음 XML 구성을 고려해 보세요:
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
Spring 컨테이너는 단일 HTTP 세션의 수명 기간 동안userPreferences 빈 정의를 사용하여 UserPreferences 빈의 새 인스턴스를 생성합니다. 즉, userPreferences 빈은 HTTP 세션 수준에서 효과적으로 범위가 지정됩니다. 요청 범위가 지정된 빈과 마찬가지로, 생성된 인스턴스의 내부 상태를 원하는 만큼 변경할 수 있으며, 동일한 userPreferences 빈 정의에서 생성된 인스턴스를 사용하는 다른 HTTP 세션 인스턴스는 개별 HTTP 세션에만 해당되므로 이러한 상태 변경이 표시되지 않는다는 것을 알 수 있습니다. HTTP 세션이 최종적으로 폐기되면 해당 특정 HTTP세션으로 범위가 지정된 빈도 폐기됩니다.
어노테이션 기반 컴포넌트 또는 Java 구성을 사용하는 경우@SessionScope 어노테이션을 사용하여 세션 스코프에 컴포넌트를 할당할 수 있습니다.
@SessionScope
@Component
public class UserPreferences {
// ...
}
애플리케이션 범위
빈 정의에 대한 다음 XML 구성을 고려해 보세요:
<bean id="appPreferences" class="com.something.AppPreferences" scope="application"/>
Spring 컨테이너는 전체 웹 애플리케이션에 대해appPreferences 빈 정의를 한 번 사용하여 AppPreferences 빈의 새 인스턴스를 생성합니다. 즉,appPreferences 빈은 ServletContext 수준에서 범위가 지정되고 일반ServletContext 속성으로 저장됩니다. 이것은 Spring 싱글톤 빈과 다소 유사하지만 두 가지 중요한 점에서 다릅니다: SpringApplicationContext (특정 웹 애플리케이션에 여러 개가 있을 수 있음)가 아닌 ServletContext별 싱글톤이며, 실제로 노출되므로 ServletContext 어트리뷰트로 볼 수 있습니다.
어노테이션 기반 컴포넌트 또는 Java 구성을 사용하는 경우@ApplicationScope 어노테이션을 사용하여 컴포넌트를 애플리케이션 범위에 할당할 수 있습니다. 다음 예제는 그 방법을 보여줍니다:
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
웹소켓 범위
WebSocket 범위는 WebSocket 세션의 라이프사이클과 연관되어 있으며 WebSocket 애플리케이션을 통한 STOMP에 적용됩니다(자세한 내용은WebSocket 범위를 참조하세요).
종속성으로 범위 지정된 빈
Spring IoC 컨테이너는 객체(빈)의 인스턴스화뿐만 아니라 공동 작업자(또는 종속성)의 배선도 관리합니다. 예를 들어 HTTP 요청 범위의 빈을 더 긴 범위의 다른 빈에 주입하려는 경우, 범위가 지정된 빈 대신 AOP 프록시를 주입하도록 선택할 수 있습니다. 즉, 범위가 지정된 객체와 동일한 공용 인터페이스를 노출하지만 관련 범위(예: HTTP 요청)에서 실제 대상 객체를 검색하고 메서드 호출을 실제 객체에 위임할 수 있는 프록시 객체를 삽입해야 합니다.
또한 싱글톤으로 범위가 지정된 빈 사이에 <aop:scoped-proxy/>를 사용할 수 있으며, 참조는 직렬화 가능하므로 역직렬화 시 대상 싱글톤 빈을 다시 가져올 수 있는 중간 프록시를 거치게 됩니다.
범위 프로토타입 빈에 대해 <aop:scoped-proxy/>를 선언하면 공유 프록시에서 메서드를 호출할 때마다 호출이 전달되는 새 대상 인스턴스가 생성됩니다.
또한 범위 프록시는 라이프사이클에 안전한 방식으로 더 짧은 범위의 빈에 액세스할 수 있는 유일한 방법은 아닙니다. 또한 주입 지점(즉, 생성자 또는 설정자 인수 또는 자동 연결 필드)을 ObjectFactory<MyTargetBean>으로 선언하여 인스턴스를 보유하거나 별도로 저장하지 않고 필요할 때마다 필요할 때마다 getObject() 호출이 현재 인스턴스를 검색할 수 있도록 할 수 있습니다.
확장된 변형으로, getIfAvailable 및 getIfUnique를 포함한 몇 가지 추가 액세스 변형을 제공하는 ObjectProvider<MyTargetBean>을 선언할 수 있습니다.
이에 대한 JSR-330 변형을 Provider라고 하며, 모든 검색 시도에 대해 Provider<MyTargetBean>선언 및 해당 get() 호출과 함께 사용됩니다. JSR-330 전반에 대한 자세한 내용은 여기를 참조하세요.
|
다음 예제의 구성은 한 줄에 불과하지만, 그 뒤에 있는 "왜"와 "어떻게"를 이해하는 것이 중요합니다:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- an HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
<!-- instructs the container to proxy the surrounding bean -->
<aop:scoped-proxy/>
</bean>
<!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.something.SimpleUserService">
<!-- a reference to the proxied userPreferences bean -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
</beans>
프록시를 정의하는 줄입니다. |
이러한 프록시를 만들려면 범위가 지정된 빈 정의에 하위 <aop:scoped-proxy/> 요소를 삽입합니다(만들 프록시 유형 선택하기및 XML 스키마 기반 구성 참조).
일반적인 시나리오에서 요청, 세션 및 사용자 지정 범위 수준에서 범위가 지정된 빈 정의에 <aop:scoped-proxy/> 요소가 필요한 이유는 무엇입니까? 다음 싱글톤 빈 정의를 고려하고 앞서 언급한 범위에 대해 정의해야 하는 것과 대조해 보세요(다음userPreferences 빈 정의는 불완전하다는 점에 유의하세요):
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
<bean id="userManager" class="com.something.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
앞의 예제에서는 싱글톤 빈(userManager)에 HTTP 세션 범위 빈(userPreferences)에 대한 참조가 삽입되어 있습니다. 여기서 중요한 점은userManager 빈이 싱글톤이라는 점입니다. 컨테이너당 정확히 한 번만 인스턴스화되고, 그 종속성(이 경우 사용자Preferences 빈 하나만)도 한 번만 주입된다는 점입니다. 즉, userManager 빈은 정확히 동일한 userPreferences 객체(즉, 원래 주입된 객체)에서만 작동합니다.
이는 수명이 짧은 범위의 빈을 수명이 긴 범위의 빈에 주입할 때 원하는 동작이 아닙니다(예: HTTP 세션 범위의 협업 빈을 싱글톤 빈에 종속성으로 주입하는 경우). 그 대신, 단일 userManager객체가 필요하며, HTTP 세션의 수명 동안에는 HTTP 세션에 특정한 userPreferences 객체가 필요합니다. 따라서 컨테이너는 UserPreferences 클래스와 정확히 동일한 공용 인터페이스를 노출하는 객체(이상적으로는 UserPreferences 인스턴스인 객체)를 생성하여 스코핑 메커니즘(HTTP 요청, Session 등)에서 실제UserPreferences 객체를 가져올 수 있습니다. 컨테이너는 이 프록시 객체를 userManager 빈에 주입하는데, 이 빈은 이 UserPreferences 참조가 프록시라는 것을 인식하지 못합니다. 이 예제에서UserManager 인스턴스가 종속성이 주입된 UserPreferences객체에서 메서드를 호출하면 실제로는 프록시에서 메서드를 호출하는 것입니다. 그런 다음 프록시는 (이 경우) HTTP 세션에서 실제UserPreferences 객체를 가져오고 메서드 호출을 검색된 실제 UserPreferences 객체에 위임합니다.
따라서 다음 예시와 같이요청 및 세션 범위의 빈을 협업 객체에 주입할 때는 다음과 같은 (정확하고 완전한) 구성이 필요합니다:
<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.something.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
생성할 프록시 유형 선택
기본적으로 Spring 컨테이너가 <aop:scoped-proxy/> 요소로 마크업된 빈에 대한 프록시를 생성할 때 CGLIB 기반 클래스 프록시가 생성됩니다.
CGLIB 프록시는 비공개 메서드를 가로채지 않습니다. 이러한 프록시에서 비공개 메서드를 호출하려고 시도하면 실제 범위가 지정된 대상 객체에 위임되지 않습니다.
|
또는, <aop:scoped-proxy/> 요소의 proxy-target-class 속성 값에 false를 지정하여 이러한 범위 지정 빈에 대한 표준 JDK 인터페이스 기반 프록시를 생성하도록 Spring 컨테이너를 구성할 수 있습니다. JDK 인터페이스 기반 프록시를 사용하면 이러한 프록시에 영향을 주기 위해 애플리케이션 클래스 경로에 추가 라이브러리가 필요하지 않습니다. 그러나 범위 지정 빈의 클래스는 하나 이상의 인터페이스를 구현해야 하며 범위 지정 빈이 주입되는 모든 공동 작업자는 해당 인터페이스 중 하나를 통해 빈을 참조해야 한다는 의미이기도 합니다. 다음 예는 인터페이스 기반 프록시를 보여줍니다:
<!-- DefaultUserPreferences implements the UserPreferences interface -->
<bean id="userPreferences" class="com.stuff.DefaultUserPreferences" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<bean id="userManager" class="com.stuff.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
클래스 기반 또는 인터페이스 기반 프록시 선택에 대한 자세한 내용은 프록시 메커니즘을 참조하세요.
요청/세션 참조 직접 주입
팩토리 스코프에 대한 대안으로, 스프링 웹 애플리케이션 컨텍스트는 다른 빈에 대한 일반 주입 지점 옆에 있는 유형 기반 자동 배선을 통해 스프링 관리 빈에 HttpServletRequest, HttpServletResponse, HttpSession,WebRequest 및 (JSF가 있는 경우) FacesContext 및 ExternalContext를 주입하는 것도 지원합니다. Spring은 일반적으로 이러한 요청 및 세션 객체에 대한 프록시를 주입하는데, 이는 팩토리 범위가 지정된 빈의 범위 지정 프록시와 유사하게 싱글톤 빈과 직렬화 가능한 빈에서도 작동한다는 장점이 있습니다.
Custom Scopes
빈 스코핑 메커니즘은 확장 가능합니다. 자체 범위를 정의하거나 기존 범위를 재정의할 수도 있지만, 후자는 잘못된 관행으로 간주되며 기본 제공 싱글톤 및 프로토타입 범위를 재정의할 수 없습니다.
사용자 지정 범위 만들기
사용자 정의 스코프를 Spring 컨테이너에 통합하려면 이 섹션에 설명된org.springframework.beans.factory.config.Scope 인터페이스를 구현해야 합니다. 자체 스코프를 구현하는 방법에 대한 아이디어는 Spring 프레임워크 자체와 함께 제공되는 Scope구현과 구현해야 하는 메서드를 더 자세히 설명하는Scope 자바독을 참조하세요.
Scope 인터페이스에는 스코프에서 객체를 가져오고, 스코프에서 객체를 제거하고, 객체를 소멸시키는 네 가지 메서드가 있습니다.
예를 들어 세션 범위 구현은 세션 범위의 빈을 반환합니다(빈이 존재하지 않으면 나중에 참조할 수 있도록 세션에 바인딩한 후 새 빈 인스턴스를 반환합니다). 다음 메서드는 기본 범위에서 객체를 반환합니다:
Object get(String name, ObjectFactory<?> objectFactory)
예를 들어 세션 범위 구현은 기본 세션에서 세션 범위 빈을 제거합니다. 객체가 반환되어야 하지만 지정된 이름의 객체를 찾을 수 없는 경우 null을 반환할 수 있습니다. 다음 메서드는 기본 범위에서 객체를 제거합니다:
Object remove(String name)
다음 메서드는 스코프가 소멸되거나 스코프의 지정된 객체가 소멸될 때 호출해야 하는 콜백을 등록합니다:
void registerDestructionCallback(String name, Runnable destructionCallback)
소멸 콜백에 대한 자세한 내용은 자바독또는 스프링 스코프 구현을 참조하세요.
다음 메서드는 기본 스코프의 대화 식별자를 가져옵니다:
String getConversationId()
이 식별자는 각 스코프마다 다릅니다. 세션 범위 구현의 경우 이 식별자는 세션 식별자가 될 수 있습니다.
사용자 지정 범위 사용하기
하나 이상의 사용자 정의 스코프 구현을 작성하고 테스트한 후에는 Spring 컨테이너가 새 스코프를 인식하도록 해야 합니다. 다음 메서드는 Spring 컨테이너에 새 Scope를 등록하는 핵심 메서드입니다:
void registerScope(String scopeName, Scope scope);
이 메서드는 Spring과 함께 제공되는 대부분의 구체적인 ApplicationContext구현에서 BeanFactory 속성을 통해 사용할 수 있는 ConfigurableBeanFactory 인터페이스에 선언되어 있습니다.
RegisterScope(..) 메서드의 첫 번째 인수는 범위와 연관된 고유 이름입니다. Spring 컨테이너 자체에서 이러한 이름의 예로는 싱글톤과프로토타입이 있습니다. RegisterScope(..) 메서드의 두 번째 인수는 등록하고 사용하려는 사용자 정의 Scope 구현의 실제 인스턴스입니다.
사용자 정의 Scope 구현을 작성한 다음 다음 예제와 같이 등록한다고 가정해 보겠습니다.
다음 예제에서는 Spring에 포함되어 있지만 기본적으로 등록되지 않은 SimpleThreadScope를 사용합니다. 사용자 정의 Scope구현에 대한 지침은 동일합니다 |
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
그런 다음 다음과 같이 사용자 정의Scope의 범위 지정 규칙을 준수하는 빈 정의를 만들 수 있습니다:
<bean id="..." class="..." scope="thread">
사용자 지정 범위 구현을 사용하면 범위를 프로그래밍 방식으로 등록하는 데 제한되지 않습니다. 다음 예시에서 보듯이CustomScopeConfigurer 클래스를 사용하여 선언적으로 범위 등록을 수행할 수도 있습니다:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
<bean id="thing2" class="x.y.Thing2" scope="thread">
<property name="name" value="Rick"/>
<aop:scoped-proxy/>
</bean>
<bean id="thing1" class="x.y.Thing1">
<property name="thing2" ref="thing2"/>
</bean>
</beans>
FactoryBean 구현에 대한 <bean> 선언 내에 <aop:scoped-proxy/>를 배치하면 범위가 지정되는 것은 getObject()에서 반환된 객체가 아니라 팩토리 빈 자체입니다 |
'언어 > Spring Docs 번역' 카테고리의 다른 글
Core Technologies / Validation, Data Binding, and Type Conversion (0) | 2024.07.07 |
---|---|
Core Technologies / Resources (0) | 2024.07.07 |
Core Technologies / The IoC Container(2) (0) | 2024.07.07 |
Core Technologies (0) | 2024.07.07 |
Spring Framework Overview (0) | 2024.07.07 |