Container Extension Points

Dev.Hammy·2024년 2월 11일
0

일반적으로 애플리케이션 개발자는 하위 클래스로ApplicationContext 구현할 필요가 없습니다. 대신, 특수 통합(integration) 인터페이스 구현을 플러그인하여 Spring IoC 컨테이너를 확장할 수 있습니다. 다음 몇 섹션에서는 이러한 통합 인터페이스에 대해 설명합니다.

Customizing Beans by Using aBeanPostProcessor

BeanPostProcessor 인터페이스는 자신만의 인스턴스화 논리(또는 컨테이너의 기본 인스턴스화를 재정의), 종속성 resolution 논리 등을 제공하기 위해 구현할 수 있는 콜백 메서드를 정의합니다. Spring 컨테이너가 인스턴스화, 구성(configuration) 및 bean 초기화를 마친 후에 이어지는 일부 사용자 정의 논리를 구현하려는 경우 하나 이상의 사용자 정의 BeanPostProcessor 구현을 플러그인할 수 있습니다.

여러 개의 BeanPostProcessor 인스턴스를 구성할 수 있으며 order 속성(property)을 설정하여 이러한 BeanPostProcessor 인스턴스가 실행되는 순서를 제어할 수 있습니다. BeanPostProcessorOrdered 인터페이스를 구현하는 경우에만 이 속성(property)을 설정할 수 있습니다. 자신만의 BeanPostProcessor를 작성한다면 Ordered 인터페이스 구현도 고려해야 합니다. 자세한 내용은 BeanPostProcessorOrdered 인터페이스의 javadoc를 참조하세요. BeanPostProcessor 인스턴스의 프로그래밍 방식 등록에 대한 참고 사항도 참조하세요.

[Note]
BeanPostProcessor 인스턴스는 Bean(또는 객체) 인스턴스에서 작동합니다. 즉, Spring IoC 컨테이너는 빈 인스턴스를 인스턴스화한 다음, BeanPostProcessor 인스턴스가 작업을 수행한다는 말입니다.

BeanPostProcessor 인스턴스는 per-container로 범위가 지정됩니다. 이는 컨테이너 계층을 사용하는 경우에만 관련됩니다. 하나의 컨테이너에 BeanPostProcessor를 정의하면 해당 컨테이너의 Bean만 사후 처리합니다. 즉, 한 컨테이너에 정의된 Bean은 두 컨테이너가 모두 동일한 계층 구조에 속하더라도 다른 컨테이너에 정의된 BeanPostProcessor에 의해 사후 처리되지 않습니다.

실제 빈 정의(즉, 빈을 정의하는 청사진)를 변경하려면, BeanFactoryPostProcessor로 구성 메타데이터 사용자 정의하기에 설명된 대로, 대신 BeanFactoryPostProcessor를 사용해야 합니다.

org.springframework.beans.factory.config.BeanPostProcessor 인터페이스는 정확히 두 개의 콜백 메소드로 구성됩니다. 이러한 클래스가 컨테이너에 사후 프로세서로 등록되면 컨테이너에 의해 생성된 각 Bean 인스턴스에 대해 사후 프로세서는 컨테이너 초기화 메서드(예: InitializingBean.afterPropertiesSet() 또는 선언된 init 메소드)가 호출되고 Bean 초기화 콜백 이후에 호출됩니다. 후처리자(post-processor)는 콜백을 완전히 무시하는 것을 포함하여 Bean 인스턴스에 대해 모든 작업을 수행할 수 있습니다. Bean 사후 프로세서는 일반적으로 콜백 인터페이스를 확인하거나 프록시로 Bean을 래핑할 수 있습니다. 일부 Spring AOP 인프라 클래스는 프록시 래핑 논리를 제공하기 위해 Bean 사후 프로세서로 구현됩니다.

ApplicationContextBeanPostProcessor 인터페이스를 구현하는 구성 메타데이터에 정의된 모든 Bean을 자동으로 감지합니다. ApplicationContext는 이러한 Bean을 사후 프로세서로 등록하여 나중에 Bean 생성 시 호출할 수 있도록 합니다. Bean 후처리자는 다른 Bean과 동일한 방식으로 컨테이너에 배치될 수 있습니다.

구성(configuration) 클래스에서 @Bean 팩토리 메소드를 사용하여 BeanPostProcessor를 선언할 때 팩토리 메소드의 반환 유형은 구현 클래스 자체이거나 최소한 org.springframework.beans.factory.config.BeanPostProcessor 인터페이스여야 하며, 해당 Bean의 사후 프로세서의 nature를 명백하게 나타내야 합니다. 그렇지 않으면 ApplicationContext는 bean이 완전히 생성되기 전, by type 방식으로 자동 감지할 수 없습니다. BeanPostProcessor는 컨텍스트에서 다른 Bean의 초기화에 적용하기 위해 먼저(early) 인스턴스화되어야 하기 때문에, 이러한 초기(early) type 감지가 중요합니다.

[Note]
프로그래밍 방식으로 BeanPostProcessor 인스턴스 등록하기
BeanPostProcessor 등록에 권장되는 접근 방식은 ApplicationContext 자동 감지(앞서 설명한 대로)를 통한 것이지만 addBeanPostProcessor 메소드를 사용하여 ConfigurableBeanFactory에 대해(against) 프로그래밍 방식으로 등록할 수 있습니다. 이는 등록 전에 조건부 논리를 평가해야 하거나 계층 구조의 컨텍스트 전체에 걸쳐 Bean 사후 프로세서를 복사해야 할 때 유용할 수 있습니다. 그러나 프로그래밍 방식으로 추가된 BeanPostProcessor 인스턴스는 Ordered 인터페이스를 따르지 않습니다. 여기서 실행 순서를 결정하는 것은 등록 순서입니다. 프로그래밍 방식으로 등록된 BeanPostProcessor 인스턴스는 명시적인 순서에 관계없이 항상 자동 감지를 통해 등록된 인스턴스보다 먼저 처리됩니다.

[Note]
BeanPostProcessor 인스턴스 및 AOP 자동 프록시
BeanPostProcessor 인터페이스를 구현하는 클래스는 특별하며 컨테이너에 의해 다르게 처리됩니다. 직접 참조하는 모든 BeanPostProcessor 인스턴스와 빈은 ApplicationContext의 특수 시작 단계의 일부로서, 시작 시 인스턴스화됩니다. 다음으로 모든 BeanPostProcessor 인스턴스는 정렬된 방식으로 등록되고 컨테이너의 모든 추가 Bean에 적용됩니다. 왜냐하면, AOP 자동 프록시는 BeanPostProcessor 자체로 구현되기 때문에, BeanPostProcessor 인스턴스나 그들이 직접 참조하는 Bean은 자동 프록시에 적합하지 않으므로 그들에게 포함되는 aspects woven이 없습니다.


AOP와 Bean Post Processor
AOP(Aspect-Oriented Programming)는 프로그래밍에서 관심사를 모듈화하고 분리하여 코드의 재사용성과 유지보수성을 향상시키는 기술입니다.

Proxy는 다른 객체에 대한 대리자 역할을 하는 객체를 말합니다. 이것은 클라이언트가 직접 객체에 접근하는 대신에 프록시를 통해 객체에 간접적으로 접근하게 하는데 사용됩니다. Proxy는 주로 보안, 로깅, 트랜잭션 처리 등과 같은 부가적인 기능을 추가하기 위해 사용됩니다.

Auto-proxying은 스프링에서 AOP를 구현하는 방법 중 하나입니다. 이것은 스프링 컨테이너가 빈을 만들 때 자동으로 프록시를 생성하여 AOP를 적용하는 것을 의미합니다. 스프링에서는 AOP를 적용하기 위해 프록시를 사용하거나 빈의 생성 및 수정 과정에 BeanPostProcessor를 사용하는데, 이것이 auto-proxying의 핵심 메커니즘입니다

BeanPostProcessor는 스프링 프레임워크에서 빈(Bean)을 초기화하고 수정하는 데 사용되는 인터페이스입니다. 이 인터페이스를 구현한 클래스는 스프링 컨테이너가 빈을 만들거나 수정할 때 특별한 방식으로 처리됩니다.

여기서 Aspect와 BeanPostProcessor의 관련성이 나타납니다. AOP는 주로 AspectJ와 같은 라이브러리를 사용하여 구현됩니다. 이러한 AOP 라이브러리는 Aspect를 적용하기 위해 BeanPostProcessor와 같은 메커니즘을 사용합니다. AspectJ의 경우, AspectJ 라이브러리는 컴파일 타임이나 런타임에 Aspect를 자바 클래스에 "woven"합니다. 이것은 AspectJ 컴파일러나 런타임이 빈을 만들거나 수정할 때 BeanPostProcessor를 사용하여 Aspect를 적용하는 것과 유사한 방식으로 작동합니다.

AOP auto-proxying이 BeanPostProcessor를 사용하여 구현되어 있지만 BeanPostProcessor 인스턴스나 그들이 직접 참조하는 빈에 대해서는 적용되지 않는 이유는 다음과 같습니다:

  1. 순서 문제: BeanPostProcessor는 빈이 생성되고 초기화되기 전과 후에 호출됩니다. 그러나 AOP auto-proxying은 빈이 생성된 후에 해당 빈에 적용됩니다. 따라서 BeanPostProcessor 인스턴스 자체나 그들이 참조하는 빈들에 대한 AOP auto-proxying은 BeanPostProcessor가 이미 적용된 이후에 발생하므로 순서적으로 적용되지 않습니다.

  2. 무한 루프와 충돌 방지: BeanPostProcessor 인스턴스나 그들이 참조하는 빈들에 대해 AOP auto-proxying을 적용하면 무한 루프가 발생할 수 있습니다. 즉, BeanPostProcessor를 통해 빈을 수정하고, 그 수정된 빈을 다시 BeanPostProcessor가 처리하고, 이런 식으로 계속됩니다. 이는 예기치 않은 동작을 초래할 수 있으며, 이를 방지하기 위해 BeanPostProcessor와 AOP auto-proxying은 별도로 처리됩니다.

따라서 BeanPostProcessor 인스턴스나 그들이 참조하는 빈들은 AOP auto-proxying 대상이 아닙니다. 이로써 AOP auto-proxying이 예상치 않은 동작이나 무한 루프와 같은 문제를 일으키는 것을 방지하고, 스프링 애플리케이션의 안정성을 유지할 수 있습니다.


어떤 경우에도
해당 bean의 경우 다음과 같은 정보 로그 메시지가 표시되어야 합니다. Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying) Bean someBean은 모든 BeanPostProcessor 인터페이스에서 처리할 수 없습니다(예: 자동 프록시에 적합하지 않음).

autowiring 또는 @Resource(autowiring으로 대체될 수 있음)를 사용하여 BeanPostProcessor에 빈을 연결한 경우 Spring이 타입 매칭 종속성 후보를 검색할 때 예기치 않은 빈에 액세스할 수 있으므로 자동 프록시 또는 다른 종류의 빈 후처리 과정에 적합하지 않게 만듭니다. 예를 들어 필드 또는 setter 이름이 Bean의 선언된 이름과 직접적으로 일치하지 않고 name 속성(attribue)이 사용되지 않는 @Resource 어노테이션이 달린 종속성이 있는 경우 Spring은 by type으로 일치시키기 위해 다른 Bean에 액세스합니다.

다음 예제는 ApplicationContext에서 BeanPostProcessor 인스턴스를 작성, 등록 및 사용하는 방법을 보여줍니다.

Example: Hello World, BeanPostProcessor-style

이 첫 번째 예는 기본적인 사용법을 보여줍니다. 예제는 컨테이너에 의해 생성된 각 Bean의 toString() 메소드를 호출하고 결과 문자열을 시스템 콘솔에 인쇄하는 사용자 정의 BeanPostProcessor 구현을 보여줍니다.

다음 목록은 사용자 정의 BeanPostProcessor 구현 클래스 정의를 보여줍니다.

package scripting;

import org.springframework.beans.factory.config.BeanPostProcessor;

public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {

	// simply return the instantiated bean as-is
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean; // we could potentially return any object reference here...
	}

	public Object postProcessAfterInitialization(Object bean, String beanName) {
		System.out.println("Bean '" + beanName + "' created : " + bean.toString());
		return bean;
	}
}

다음 bean 요소는 InstantiationTracingBeanPostProcessor를 사용합니다.

<?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:lang="http://www.springframework.org/schema/lang"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/lang
		https://www.springframework.org/schema/lang/spring-lang.xsd">

	<lang:groovy id="messenger"
			script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
		<lang:property name="message" value="Fiona Apple Is Just So Dreamy."/>
	</lang:groovy>

	<!--
	when the above bean (messenger) is instantiated, this custom
	BeanPostProcessor implementation will output the fact to the system console
	-->
	<bean class="scripting.InstantiationTracingBeanPostProcessor"/>

</beans>

InstantiationTracingBeanPostProcessor가 어떻게 정의되었는지 주목하세요. 이름도 없고 Bean이므로 다른 Bean과 마찬가지로 종속성을 주입할 수 있습니다. (이전 구성은 Groovy 스크립트가 지원하는(backed by) Bean도 정의합니다. Spring 동적 언어 지원은 동적 언어 지원 장에 자세히 설명되어 있습니다.)

다음 Java 애플리케이션은 이전 코드와 구성을 실행합니다.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;

public final class Boot {

	public static void main(final String[] args) throws Exception {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml");
		Messenger messenger = ctx.getBean("messenger", Messenger.class);
		System.out.println(messenger);
	}

}

이전 애플리케이션의 출력은 다음과 유사합니다.

Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961
org.springframework.scripting.groovy.GroovyMessenger@272961

Example: The AutowiredAnnotationBeanPostProcessor

사용자 정의 BeanPostProcessor 구현과 함께(in conjunction with) 콜백 인터페이스 또는 어노테이션을 사용하는 것은 Spring IoC 컨테이너를 확장(extending)하는 일반적인 방법입니다. 예를 들어 Spring의 AutowiredAnnotationBeanPostProcessor 는 Spring 배포판과 함께 제공되고 주석이 달린 필드, setter 메소드 및 임의 구성 메소드를 자동 연결하는 BeanPostProcessor 구현입니다.

Customizing Configuration Metadata with a BeanFactoryPostProcessor

우리가 살펴볼 다음 확장점은 org.springframework.beans.factory.config.BeanFactoryPostProcessor입니다. 이 인터페이스의 의미(seantics)는 BeanPostProcessor의 의미와 유사하지만 한 가지 주요 차이점은 BeanFactoryPostProcessor가 빈 구성 메타데이터에서 작동한다는 것입니다. 즉, Spring IoC 컨테이너는 BeanFactoryPostProcessor가 구성 메타데이터를 읽고 잠재적으로 컨테이너가 BeanFactoryPostProcessor 인스턴스 이외의 빈을 인스턴스화하기 전에 이를 변경할 수 있도록 합니다.

여러 개의 BeanFactoryPostProcessor 인스턴스를 구성할 수 있으며 order 속성(property)을 설정하여 이러한 BeanFactoryPostProcessor 인스턴스가 실행되는 순서를 제어할 수 있습니다. 그러나 BeanFactoryPostProcessorOrdered 인터페이스를 구현하는 경우에만 이 속성을 설정할 수 있습니다. 자신만의 BeanFactoryPostProcessor를 작성한다면 Ordered 인터페이스 구현도 고려해야 합니다. 자세한 내용은 BeanFactoryPostProcessorOrdered 인터페이스의 javadoc를 참조하세요.

[Note]
실제 빈 인스턴스(즉, 구성 메타데이터에서 생성된 객체)를 변경하려면 대신 BeanPostProcessor를 사용해야 합니다(앞서 BeanPostProcessor를 사용하여 빈 사용자 정의하기에서 설명). BeanFactoryPostProcessor 내에서 Bean 인스턴스로 작업하는 것이 기술적으로 가능하지만(예: BeanFactory.getBean() 사용) 그렇게 하면 조기(premature) Bean 인스턴스화가 발생하여 표준 컨테이너 lifecycle를 위반하게 됩니다. 이는 Bean 사후 처리를 우회하는 등 부정적인 부작용을 일으킬 수 있습니다.

또한 BeanFactoryPostProcessor 인스턴스는 per-container로 범위가 지정됩니다. 이는 컨테이너 계층 구조를 사용하는 경우에만 관련됩니다. 하나의 컨테이너에 BeanFactoryPostProcessor를 정의하면 해당 컨테이너의 Bean 정의에만 적용됩니다. 한 컨테이너의 Bean 정의는 두 컨테이너가 동일한 계층의 일부인 경우에도 다른 컨테이너의 BeanFactoryPostProcessor 인스턴스에 의해 사후 처리되지 않습니다.

Bean 팩토리 후처리자(post-processor)는 컨테이너를 정의하는 구성 메타데이터에 변경사항을 적용하기 위해 ApplicationContext 내에서 선언될 때 자동으로 실행됩니다. Spring에는 PropertyOverrideConfigurerPropertySourcesPlaceholderConfigurer와 같은 사전 정의된 여러 Bean 팩토리 후처리기가 포함되어 있습니다. 예를 들어 사용자 정의 속성 편집기를 등록하기 위해 사용자 정의 BeanFactoryPostProcessor를 사용할 수도 있습니다.

ApplicationContextBeanFactoryPostProcessor 인터페이스를 구현하는, 모든 배포된 Bean을 자동으로 감지합니다. 적절한 시간에 이러한 Bean을 Bean Factory 후처리자로 사용합니다. 다른 Bean과 마찬가지로 이러한 사후 프로세서 Bean을 배포할 수 있습니다.

[Note]
BeanPostProcessors와 마찬가지로 일반적으로 지연 초기화를 위해 BeanFactoryPostProcessors를 구성하고 싶지 않을 것입니다. 다른 Bean이 Bean(Factory)PostProcessor를 참조하지 않으면 해당 사후 프로세서는 전혀 인스턴스화되지 않습니다. 따라서 지연 초기화로 표시하는 것은 무시되며 <beans /> 요소 선언에서 default-lazy-init 속성을 true로 설정하더라도 Bean(Factory)PostProcessor는 즉시 인스턴스화됩니다.

Example : The Class Name Substitution PropertySourcesPlacdeholderConfigurer

PropertySourcesPlaceholderConfigurer는 표준 Java Properties 형식을 사용하여 별도의 파일에 있는 Bean 정의의 속성 값을 외부화(externalize)합니다. 이렇게 하면 애플리케이션을 배포하는 사람이 기본 XML 정의 파일이나 컨테이너용 파일을 수정하는 복잡성이나 위험 없이 데이터베이스 URL 및 비밀번호와 같은 환경별 속성을 사용자 정의할 수 있습니다.

자리 표시자(placeholder) 값이 있는 DataSource가 정의된 다음 XML 기반 구성 메타데이터 조각을 고려하세요.

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
	<property name="locations" value="classpath:com/something/jdbc.properties"/>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName" value="${jdbc.driverClassName}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</bean>

이 예에서는 외부 Properties 파일에서 구성된 속성을 보여줍니다. 런타임 시 DataSource의 일부 속성을 대체하는 메타데이터에 PropertySourcesPlaceholderConfigurer가 적용됩니다. 대체할 값은 Ant, log4j 및 JSP EL 스타일을 따르는 ${property-name} 형식의 자리 표시자로 지정됩니다.

실제 값은 표준 Java Properties 형식의 다른 파일에서 가져옵니다.

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

따라서 ${jdbc.username} 문자열은 런타임 시 'sa' 값으로 대체되며, 속성 파일의 키와 일치하는 다른 자리 표시자 값에도 동일하게 적용됩니다. PropertySourcesPlaceholderConfigurer는 빈 정의의 대부분의 속성(properties)과 속성(attributes)에서 자리 표시자를 확인합니다. 또한 자리 표시자 접두사 및 접미사를 사용자 정의할 수 있습니다.

Spring 2.5에 도입된 context 네임스페이스를 사용하면 전용 구성 요소로 속성 자리 표시자를 구성할 수 있습니다. 다음 예와 같이 location 속성(attribute)에 하나 이상의 위치를 쉼표로 구분된 목록으로 제공할 수 있습니다.

<context:property-placeholder location="classpath:com/something/jdbc.properties"/>

PropertySourcesPlaceholderConfigurer는 사용자가 지정하는 Properties 파일에서 속성(property)을 찾을 뿐만 아니라 기본적으로 지정된 속성 파일에서 속성을 찾을 수 없으면 Spring Environment 속성(property)과 일반 Java System 속성(property)을 확인합니다.

[Warning]
필요한 속성을 가진 특정 애플리케이션에 대해 그러한 요소 하나만 정의해야 합니다. 고유한 자리 표시자 구문(${…​})이 있어야 여러 속성 자리 표시자를 구성할 수 있습니다.

교체에 사용되는 속성 소스를 모듈화해야 하는 경우 여러 속성 자리 표시자를 생성하면 안 됩니다. 오히려 사용할 속성을 수집하는 자체 PropertySourcesPlaceholderConfigurer 빈을 생성해야 합니다.

[Tip]
PropertySourcesPlaceholderConfigurer를 사용하여 클래스 이름을 대체할 수 있습니다. 이는 런타임 시 특정 구현 클래스를 선택해야 할 때 유용할 때가 있습니다. 다음 예에서는 그 방법을 보여줍니다.

<bean class="org.springframework.beans.factory.config.PropertySourcesPlaceholderConfigurer">
	<property name="locations">
		<value>classpath:com/something/strategy.properties</value>
	</property>
	<property name="properties">
		 <value>custom.strategy.class=com.something.DefaultStrategy</value>
	</property>
 </bean>
<bean id="serviceStrategy" class="${custom.strategy.class}"/>

클래스가 런타임에 유효한 클래스로 분석(resolve)될 수 없는 경우, 지연 초기화가 아닌 Bean에 대한 ApplicationContextpreInstantiateSingletons() 단계 중에, 빈이 생성되려고 할 때 빈 분석(resolution)이 실패합니다.

Example:The PropertyOverrideConfigurer

또 다른 빈 팩토리 후처리자인 PropertyOverrideConfigurerPropertySourcesPlaceholderConfigurer와 유사하지만 후자와는 달리 원래 정의에는 빈 속성(property)에 대한 기본값이 있거나 값이 전혀 없을 수 있습니다. 재정의하는 Properties 파일에 특정 Bean property에 대한 항목(entry)이 없으면 기본 컨텍스트 정의가 사용됩니다.

Bean 정의는 재정의된 것을 인식하지 못하므로 재정의 구성자(override configurer)가 사용되고 있다는 것이 XML 정의 파일에서 즉시 명백하지 않습니다. 동일한 Bean 속성에 대해 서로 다른 값을 정의하는 여러 PropertyOverrideConfigurer 인스턴스의 경우 재정의 메커니즘으로 인해 마지막 항목이 우선합니다.

속성 파일 구성 줄은 다음 형식을 사용합니다.

beanName.property=value

다음 목록은 형식의 예를 보여줍니다

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb

이 예제 파일은 driverurl 속성(property)이 있는 dataSource라는 Bean을 포함하는 컨테이너 정의와 함께 사용할 수 있습니다.

재정의되는 최종 속성을 제외한 경로의 모든 구성 요소가 이미 null이 아닌 경우(아마도(presumably) 생성자에 의해 초기화된 경우) 복합(compound) 속성(property) 이름도 지원됩니다. 다음 예에서는 tom bean의 fred 속성(property)에 대한 bob 속성(property)의 sammy 속성(property)이 스칼라 값 123으로 설정됩니다.

tom.fred.bob.sammy=123

[Note]
지정된 재정의 값은 항상 리터럴 값입니다. Bean 참조로 변환되지 않습니다. 이 규칙은 XML bean 정의의 원래 값이 bean 참조를 지정할 때도 적용됩니다.

Spring 2.5에 도입된 context 네임스페이스를 사용하면 다음 예제와 같이 전용 구성 요소로 속성 재정의를 구성할 수 있습니다.

<context:property-override location="classpath:override.properties"/>

Customizing Instantiation Logic with a FactoryBean

그 자체가 팩토리인 객체에 대해 org.springframework.beans.factory.FactoryBean 인터페이스를 구현할 수 있습니다.

FactoryBean 인터페이스는 Spring IoC 컨테이너의 인스턴스화 로직에 대한 연결 지점입니다. (잠재적으로) 장황한 양의 XML과 달리 Java로 더 잘 표현되는 복잡한 초기화 코드가 있는 경우 자체 FactoryBean을 생성하고 해당 클래스 내에 복잡한 초기화를 작성한 다음 사용자 정의 FactoryBean을 컨테이너에 연결할 수 있습니다.

FactoryBean<T> 인터페이스는 세 가지 메서드를 제공합니다.

  • T getObject(): 이 팩토리가 생성하는 객체의 인스턴스를 반환합니다. 이 팩토리가 싱글톤을 반환하는지 아니면 프로토타입을 반환하는지에 따라 인스턴스를 공유할 수 있습니다.

  • boolean isSingleton(): 이 FactoryBean이 싱글톤을 반환하면 true를 반환하고 그렇지 않으면 false를 반환합니다. 이 메서드의 기본 구현은 true를 반환합니다.

  • Class<?> getObjectType(): getObject() 메서드에서 반환된 객체 type을 반환하거나 type을 미리(in advance) 알 수 없는 경우 null을 반환합니다.

FactoryBean 개념과 인터페이스는 Spring Framework 내의 여러 위치에서 사용됩니다. 50개 이상의 FactoryBean 인터페이스 구현이 Spring 자체와 함께 제공됩니다.

생성된 Bean 대신 실제 FactoryBean 인스턴스 자체를 컨테이너에 요청해야 하는 경우 ApplicationContextgetBean() 메서드를 호출할 때 Bean의 id 앞에 앰퍼샌드 기호(&)를 붙입니다. 따라서 idmyBean인 특정 FactoryBean에 대해 컨테이너에서 getBean("myBean")을 호출하면 FactoryBean의 제품이 반환되는 반면, getBean("&myBean")을 호출하면 FactoryBean 인스턴스 자체가 반환됩니다.

0개의 댓글