Loading...
Spring Framework Reference Documentation 7.0.2의 Container Extension Points의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
일반적으로 애플리케이션 개발자는 ApplicationContext
구현 클래스를 서브클래싱할 필요가 없습니다. 대신 Spring IoC 컨테이너는 특수 통합 인터페이스의 구현을 플러그인하여 확장할 수 있습니다. 다음 몇 개의 섹션에서는 이러한 통합 인터페이스를 설명합니다.
BeanPostProcessor를 사용한 빈 커스터마이징BeanPostProcessor 인터페이스는 콜백 메서드를 정의하며, 이를 구현해서 컨테이너의 기본 인스턴스화 로직, 의존성 해결 로직 등을 직접 제공(또는 재정의)할 수 있습니다. Spring 컨테이너가 빈을 인스턴스화하고, 설정하고, 초기화한 이후에 일부 커스텀 로직을 구현하고 싶다면 하나 이상의 커스텀 BeanPostProcessor 구현을 플러그인할 수 있습니다.
여러 BeanPostProcessor 인스턴스를 설정할 수 있으며, order 프로퍼티를 설정하여 이러한 BeanPostProcessor 인스턴스가 실행되는 순서를 제어할 수 있습니다.
이 프로퍼티는 BeanPostProcessor가 Ordered
인터페이스를 구현한 경우에만 설정할 수 있습니다. 직접 BeanPostProcessor를 작성하는 경우에도 Ordered 인터페이스 구현을 고려해야 합니다. 자세한 내용은
BeanPostProcessor
와 Ordered 인터페이스의 javadoc을 참고하세요. 또한
BeanPostProcessor 인스턴스의 프로그래밍 방식 등록에 대한 노트도 참고하세요.
BeanPostProcessor인스턴스는 빈(또는 객체) 인스턴스에 대해 동작합니다. 즉, Spring IoC 컨테이너가 빈 인스턴스를 인스턴스화한 다음에BeanPostProcessor인스턴스가 작업을 수행합니다.BeanPostProcessor인스턴스는 컨테이너마다 스코프가 지정됩니다. 이는 컨테이너 계층 구조를 사용하는 경우에만 관련이 있습니다. 하나의 컨테이너에BeanPostProcessor를 정의하면 해당 컨테이너의 빈에만 후처리를 수행합니다. 다시 말해, 하나의 컨테이너에 정의된 빈은 동일한 계층 구조의 일부이더라도 다른 컨테이너에 정의된BeanPostProcessor에 의해 후처리되지 않습니다. 실제 빈 정의(즉, 빈을 정의하는 청사진)를 변경하려면 대신BeanFactoryPostProcessor를 사용해야 합니다. 이에 대해서는BeanFactoryPostProcessor를 사용한 설정 메타데이터 커스터마이징에서 설명합니다.
org.springframework.beans.factory.config.BeanPostProcessor 인터페이스는 정확히 두 개의 콜백 메서드로 구성됩니다. 이러한 클래스가 컨테이너에 후처리기로 등록되면, 컨테이너가 생성하는 각 빈 인스턴스에 대해
후처리기는 컨테이너 초기화 메서드(예: InitializingBean.afterPropertiesSet() 또는 선언된 init 메서드)가 호출되기 전과 모든 빈 초기화 콜백 이후에 컨테이너로부터 콜백을 받습니다.
후처리기는 콜백을 완전히 무시하는 것을 포함하여 빈 인스턴스에 대해 임의의 작업을 수행할 수 있습니다. 빈 후처리기는 일반적으로 콜백 인터페이스를 확인하거나, 프록시로 빈을 래핑할 수 있습니다. 일부 Spring AOP 인프라스트럭처 클래스는 프록시 래핑 로직을 제공하기 위해 빈 후처리기로 구현되어 있습니다.
ApplicationContext는 설정 메타데이터에 정의된 빈 중에서
BeanPostProcessor 인터페이스를 구현한 빈을 자동으로 감지합니다.
ApplicationContext는 이러한 빈을 후처리기로 등록하여 나중에 빈 생성 시 호출할 수 있도록 합니다. 빈 후처리기는 다른 빈과 동일한 방식으로 컨테이너에 배포할 수 있습니다.
설정 클래스에서 @Bean 팩토리 메서드를 사용하여 BeanPostProcessor를 선언할 때,
팩토리 메서드의 반환 타입은 구현 클래스 자체이거나 최소한
org.springframework.beans.factory.config.BeanPostProcessor
인터페이스여야 하며, 해당 빈의 후처리기 특성을 명확하게 나타내야 합니다. 그렇지 않으면
ApplicationContext는 완전히 생성되기 전에 타입으로 자동 감지할 수 없습니다.
BeanPostProcessor는 컨텍스트의 다른 빈 초기화에 적용되기 위해 일찍 인스턴스화되어야 하므로, 이러한 초기 타입 감지는 매우 중요합니다.
BeanPostProcessor인스턴스의 프로그래밍 방식 등록BeanPostProcessor등록에 권장되는 방식은 앞에서 설명한 대로ApplicationContext자동 감지를 통한 방식이지만,ConfigurableBeanFactory에 대해addBeanPostProcessor메서드를 사용하여 프로그래밍 방식으로 등록할 수도 있습니다. 이는 등록 전에 조건부 로직을 평가해야 하거나, 계층 구조 내에서 컨텍스트 간에 빈 후처리기를 복사해야 할 때 유용할 수 있습니다. 그러나 프로그래밍 방식으로 추가된BeanPostProcessor인스턴스는Ordered인터페이스를 따르지 않는다는 점에 유의해야 합니다. 여기서는 등록 순서가 실행 순서를 결정합니다. 또한 프로그래밍 방식으로 등록된BeanPostProcessor인스턴스는 명시적 순서 지정과 관계없이 자동 감지를 통해 등록된 후처리기보다 항상 먼저 처리됩니다.
BeanPostProcessor인스턴스와 AOP 자동 프록시BeanPostProcessor인터페이스를 구현하는 클래스는 특별하며 컨테이너에 의해 다르게 취급됩니다. 모든BeanPostProcessor인스턴스와 이들이 직접 참조하는 빈은ApplicationContext의 특수 시작 단계의 일부로서 시작 시점에 인스턴스화됩니다. 다음으로, 모든BeanPostProcessor인스턴스가 정렬된 방식으로 등록되고 컨테이너의 이후 모든 빈에 적용됩니다. AOP 자동 프록시가 자체적으로BeanPostProcessor로 구현되어 있기 때문에,BeanPostProcessor인스턴스와 이들이 직접 참조하는 빈은 자동 프록시 대상이 아니며, 따라서 이들에는 애스펙트가 위빙되지 않습니다.
이러한 빈에 대해서는 다음과 같은 정보 로그 메시지를 볼 수 있어야 합니다:
Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying). 자동 와이어링 또는@Resource(자동 와이어링으로 폴백될 수 있음)를 사용하여BeanPostProcessor에 빈을 와이어링한 경우, Spring은 타입 일치 의존성 후보를 검색하는 동안 예기치 않은 빈에 접근할 수 있으며, 따라서 이들을 자동 프록시 또는 다른 종류의 빈 후처리 대상에서 제외시킬 수 있습니다. 예를 들어, 필드나 세터 이름이 선언된 빈 이름과 직접적으로 일치하지 않고 name 속성이 사용되지 않은@Resource로 주석이 달린 의존성이 있는 경우, Spring은 타입으로 일치시키기 위해 다른 빈에 접근합니다.
다음 예제는 ApplicationContext에서 BeanPostProcessor 인스턴스를 작성, 등록 및 사용하는 방법을 보여줍니다.
BeanPostProcessor 스타일첫 번째 예제는 기본 사용법을 보여줍니다. 이 예제는 컨테이너에 의해 생성될 때마다 각 빈의 toString() 메서드를 호출하고 결과 문자열을 시스템 콘솔에 출력하는 커스텀
BeanPostProcessor 구현을 보여줍니다.
다음 목록은 커스텀 BeanPostProcessor 구현 클래스 정의를 보여줍니다:
1package scripting; 2 3import org.springframework.beans.factory.config.BeanPostProcessor; 4 5public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor { 6 7 // simply return the instantiated bean as-is 8 public Object postProcessBeforeInitialization(Object bean, String beanName) { 9 return bean; // we could potentially return any object reference here... 10 } 11 12 public Object postProcessAfterInitialization(Object bean, String beanName) { 13 System.out.println("Bean '" + beanName + "' created : " + bean.toString()); 14 return bean; 15 } 16}
1package scripting 2 3import org.springframework.beans.factory.config.BeanPostProcessor 4 5class InstantiationTracingBeanPostProcessor : BeanPostProcessor { 6 7 // simply return the instantiated bean as-is 8 override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any? { 9 return bean // we could potentially return any object reference here... 10 } 11 12 override fun postProcessAfterInitialization(bean: Any, beanName: String): Any? { 13 println("Bean '$beanName' created : $bean") 14 return bean 15 } 16}
다음 beans 엘리먼트는 InstantiationTracingBeanPostProcessor를 사용합니다:
1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:lang="http://www.springframework.org/schema/lang" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/lang 8 https://www.springframework.org/schema/lang/spring-lang.xsd"> 9 10 <lang:groovy id="messenger" 11 script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy"> 12 <lang:property name="message" value="Fiona Apple Is Just So Dreamy."/> 13 </lang:groovy> 14 15 <!-- 16 when the above bean (messenger) is instantiated, this custom 17 BeanPostProcessor implementation will output the fact to the system console 18 --> 19 <bean class="scripting.InstantiationTracingBeanPostProcessor"/> 20 21</beans>
InstantiationTracingBeanPostProcessor가 단순히 정의만 되어 있다는 점에 주목하세요. 이름조차 없으며, 빈이기 때문에 다른 빈과 마찬가지로 의존성 주입을 받을 수 있습니다. (앞의 설정은 Groovy
스크립트로 지원되는 빈도 정의합니다.)
다음 Java 애플리케이션은 앞의 코드와 설정을 실행합니다:
1import org.springframework.context.ApplicationContext; 2import org.springframework.context.support.ClassPathXmlApplicationContext; 3import org.springframework.scripting.Messenger; 4 5public final class Boot { 6 7 public static void main(final String[] args) throws Exception { 8 ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml"); 9 Messenger messenger = ctx.getBean("messenger", Messenger.class); 10 System.out.println(messenger); 11 } 12 13}
1import org.springframework.beans.factory.getBean 2 3fun main() { 4 val ctx = ClassPathXmlApplicationContext("scripting/beans.xml") 5 val messenger = ctx.getBean<Messenger>("messenger") 6 println(messenger) 7}
앞의 애플리케이션 출력은 다음과 비슷합니다:
1Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961 2org.springframework.scripting.groovy.GroovyMessenger@272961
AutowiredAnnotationBeanPostProcessor콜백 인터페이스나 어노테이션을 커스텀 BeanPostProcessor
구현과 함께 사용하는 것은 Spring IoC 컨테이너를 확장하는 일반적인 수단입니다. 예로는 Spring의 AutowiredAnnotationBeanPostProcessor가 있습니다. 이는 Spring 배포판에 포함된 BeanPostProcessor 구현으로, 어노테이션이 달린 필드, 세터 메서드, 임의의 설정 메서드를 자동 와이어링합니다.
BeanFactoryPostProcessor를 사용한 설정 메타데이터 커스터마이징다음으로 살펴볼 확장 지점은
org.springframework.beans.factory.config.BeanFactoryPostProcessor입니다. 이 인터페이스의 의미는 BeanPostProcessor와 유사하지만, 한 가지 큰 차이점이 있습니다:
BeanFactoryPostProcessor는 빈 설정 메타데이터에 대해 동작합니다.
즉, Spring IoC 컨테이너는 BeanFactoryPostProcessor가
설정 메타데이터를 읽고 컨테이너가
BeanFactoryPostProcessor 인스턴스를 제외한 어떤 빈도 인스턴스화하기 전에
이를 변경할 수 있도록 허용합니다.
여러 BeanFactoryPostProcessor 인스턴스를 설정할 수 있으며, order 프로퍼티를 설정하여 이러한 BeanFactoryPostProcessor 인스턴스가 실행되는 순서를 제어할 수 있습니다.
그러나 이 프로퍼티는 BeanFactoryPostProcessor가
Ordered 인터페이스를 구현한 경우에만 설정할 수 있습니다. 직접 BeanFactoryPostProcessor를 작성하는 경우에도 Ordered 인터페이스 구현을 고려해야 합니다. 자세한 내용은
BeanFactoryPostProcessor
와 Ordered 인터페이스의 javadoc을 참고하세요.
실제 빈 인스턴스(즉, 설정 메타데이터로부터 생성되는 객체)를 변경하려면 대신
BeanPostProcessor를 사용해야 합니다(앞에서 설명한BeanPostProcessor를 사용한 빈 커스터마이징 참고). 기술적으로는BeanFactoryPostProcessor내에서 빈 인스턴스로 작업하는 것이 가능하지만 (예:BeanFactory.getBean()사용), 이렇게 하면 표준 컨테이너 라이프사이클을 위반하는 조기 빈 인스턴스화를 유발합니다. 이는 빈 후처리 우회와 같은 부정적인 부작용을 초래할 수 있습니다. 또한BeanFactoryPostProcessor인스턴스는 컨테이너마다 스코프가 지정됩니다. 이는 컨테이너 계층 구조를 사용하는 경우에만 관련이 있습니다. 하나의 컨테이너에BeanFactoryPostProcessor를 정의하면 해당 컨테이너의 빈 정의에만 적용됩니다. 하나의 컨테이너에 있는 빈 정의는 다른 컨테이너의BeanFactoryPostProcessor인스턴스에 의해 후처리되지 않으며, 두 컨테이너가 동일한 계층 구조의 일부이더라도 마찬가지입니다.
빈 팩토리 후처리기는 컨테이너를 정의하는 설정 메타데이터에 변경을 적용하기 위해
ApplicationContext 내부에 선언되면 자동으로 실행됩니다. Spring에는
PropertyOverrideConfigurer 및
PropertySourcesPlaceholderConfigurer와 같은 여러 사전 정의된 빈 팩토리
후처리기가 포함되어 있습니다. 또한 커스텀 BeanFactoryPostProcessor를 사용할 수도 있습니다. 예를 들어, 커스텀 프로퍼티 에디터를 등록하기 위해 사용할 수 있습니다.
ApplicationContext는 그 안에 배포된 빈 중에서
BeanFactoryPostProcessor 인터페이스를 구현한 빈을 자동으로 감지합니다. 그리고 적절한 시점에 이러한 빈을 빈 팩토리
후처리기로 사용합니다. 이러한 후처리기 빈은 다른 빈과 동일한 방식으로 배포할 수 있습니다.
BeanPostProcessor와 마찬가지로, 일반적으로BeanFactoryPostProcessor를 지연 초기화로 설정하고 싶지는 않을 것입니다. 다른 어떤 빈도Bean(Factory)PostProcessor를 참조하지 않으면 해당 후처리기는 전혀 인스턴스화되지 않습니다. 따라서 이를 지연 초기화로 표시하는 것은 무시되며,<beans />엘리먼트 선언에서default-lazy-init속성을true로 설정하더라도Bean(Factory)PostProcessor는 즉시 인스턴스화됩니다.
PropertySourcesPlaceholderConfigurer를 사용한 프로퍼티 플레이스홀더 치환PropertySourcesPlaceholderConfigurer를 사용하여 빈 정의에서 프로퍼티 값을 별도의 파일로 외부화할 수 있으며, 표준 Java Properties 포맷을 사용합니다.
이를 통해 애플리케이션을 배포하는 사람이 컨테이너의 주요 XML 정의 파일을 수정하는 복잡성이나 위험 없이 데이터베이스 URL 및 비밀번호와 같은 환경별 프로퍼티를 커스터마이징할 수 있습니다.
다음은 플레이스홀더 값을 가진 DataSource가 정의된 XML 기반 설정 메타데이터 조각입니다:
1<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"> 2 <property name="locations" value="classpath:com/something/jdbc.properties"/> 3</bean> 4 5<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 6 <property name="driverClassName" value="${jdbc.driverClassName}"/> 7 <property name="url" value="${jdbc.url}"/> 8 <property name="username" value="${jdbc.username}"/> 9 <property name="password" value="${jdbc.password}"/> 10</bean>
이 예제는 외부 Properties 파일에서 설정된 프로퍼티를 보여줍니다. 런타임에
PropertySourcesPlaceholderConfigurer가 메타데이터에 적용되어
DataSource의 일부 프로퍼티를 치환합니다.
치환할 값은 ${property-name} 형식의 플레이스홀더로 지정되며, 이는 Ant, log4j, JSP EL 스타일을 따릅니다.
실제 값은 표준 Java Properties 포맷의 다른 파일에서 가져옵니다:
1jdbc.driverClassName=org.hsqldb.jdbcDriver 2jdbc.url=jdbc:hsqldb:hsql://production:9002 3jdbc.username=sa 4jdbc.password=root
따라서 ${jdbc.username} 문자열은 런타임에 'sa' 값으로 치환되며,
프로퍼티 파일의 키와 일치하는 다른 플레이스홀더 값에도 동일하게 적용됩니다.
PropertySourcesPlaceholderConfigurer는 대부분의 프로퍼티와
빈 정의의 속성에서 플레이스홀더를 확인합니다. 또한 플레이스홀더 접두사,
접미사, 기본값 구분자, 이스케이프 문자를 커스터마이징할 수 있습니다. 추가로,
기본 이스케이프 문자는 JVM 시스템 프로퍼티(또는
SpringProperties 메커니즘)를 통해
spring.placeholder.escapeCharacter.default 프로퍼티를 설정하여 전역적으로 변경하거나 비활성화할 수 있습니다.
context 네임스페이스를 사용하면 전용 설정 엘리먼트로 프로퍼티 플레이스홀더를 설정할 수 있습니다.
다음 예제와 같이 location 속성에 콤마로 구분된 목록으로 하나 이상의 위치를 제공할 수 있습니다:
1<context:property-placeholder location="classpath:com/something/jdbc.properties"/>
PropertySourcesPlaceholderConfigurer는 지정한 Properties
파일에서 프로퍼티를 찾는 것뿐만 아니라, 기본적으로 지정된 프로퍼티 파일에서 프로퍼티를 찾을 수 없는 경우 Spring Environment 프로퍼티와 일반 Java System 프로퍼티를 확인합니다.
애플리케이션에 필요한 프로퍼티를 가진 이러한 엘리먼트는 하나만 정의해야 합니다. 여러 프로퍼티 플레이스홀더는 서로 다른 플레이스홀더 구문(
${…})을 가진 경우에만 설정할 수 있습니다. 치환에 사용되는 프로퍼티의 소스를 모듈화해야 하는 경우, 여러 프로퍼티 플레이스홀더를 생성해서는 안 됩니다. 대신 사용할 프로퍼티를 수집하는 자체PropertySourcesPlaceholderConfigurer빈을 생성해야 합니다.
PropertySourcesPlaceholderConfigurer를 사용하여 클래스 이름을 치환할 수 있으며, 이는 런타임에 특정 구현 클래스를 선택해야 할 때 유용할 수 있습니다. 다음 예제는 이를 수행하는 방법을 보여줍니다:1<bean class="org.springframework.beans.factory.config.PropertySourcesPlaceholderConfigurer"> 2 <property name="locations"> 3 <value>classpath:com/something/strategy.properties</value> 4 </property> 5 <property name="properties"> 6 <value>custom.strategy.class=com.something.DefaultStrategy</value> 7 </property> 8</bean> 9<bean id="serviceStrategy" class="${custom.strategy.class}"/>클래스가 런타임에 유효한 클래스로 해석될 수 없는 경우, 지연 초기화가 아닌 빈에 대해
ApplicationContext의preInstantiateSingletons()단계에서 빈이 생성되려 할 때 빈 해석이 실패합니다.
PropertyOverrideConfigurer또 다른 빈 팩토리 후처리기인 PropertyOverrideConfigurer는
PropertySourcesPlaceholderConfigurer와 유사하지만, 후자의 경우와 달리 원래 정의는 빈 프로퍼티에 기본값을 갖거나 값을 전혀 갖지 않을 수 있습니다. 재정의하는
Properties 파일에 특정 빈 프로퍼티에 대한 항목이 없는 경우 기본
컨텍스트 정의가 사용됩니다.
빈 정의는 재정의되고 있다는 사실을 인식하지 못하므로,
XML 정의 파일만으로는 재정의 설정기가 사용되고 있다는 것을 즉시 알 수 없습니다.
서로 다른 PropertyOverrideConfigurer 인스턴스가 동일한 빈 프로퍼티에 대해 다른 값을 정의하는 경우, 재정의 메커니즘으로 인해 마지막 것이 우선합니다.
프로퍼티 파일 설정 라인은 다음 형식을 따릅니다:
1beanName.property=value
다음 목록은 형식의 예를 보여줍니다:
1dataSource.driverClassName=com.mysql.jdbc.Driver 2dataSource.url=jdbc:mysql:mydb
이 예제 파일은 driverClassName 및 url 프로퍼티를 가진
dataSource라는 빈이 포함된 컨테이너 정의와 함께 사용할 수 있습니다.
복합 프로퍼티 이름도 지원되며, 마지막으로 재정의되는 프로퍼티를 제외한 경로의 모든 구성 요소가 이미 null이 아니어야 합니다(생성자에 의해 초기화되었다고 가정).
다음 예제에서 tom 빈의 fred 프로퍼티의 bob 프로퍼티의 sammy 프로퍼티는 스칼라 값 123으로 설정됩니다:
1tom.fred.bob.sammy=123
지정된 재정의 값은 항상 리터럴 값입니다. 빈 참조로 변환되지 않습니다. 이 규칙은 XML 빈 정의의 원래 값이 빈 참조를 지정하는 경우에도 적용됩니다.
Spring 2.5에서 도입된 context 네임스페이스를 사용하면
다음 예제와 같이 전용 설정 엘리먼트로 프로퍼티 재정의를 설정할 수 있습니다:
1<context:property-override location="classpath:override.properties"/>
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() 메서드가 반환하는 객체 타입을 반환하거나,
타입을 미리 알 수 없는 경우 null을 반환합니다.FactoryBean 개념과 인터페이스는 Spring
Framework 내에서 여러 곳에서 사용됩니다. Spring 자체에는 50개가 넘는
FactoryBean 인터페이스 구현이 포함되어 있습니다.
컨테이너에 FactoryBean이 생성하는 빈이 아니라 실제 FactoryBean 인스턴스를 요청해야 할 때는,
ApplicationContext의 getBean() 메서드를 호출할 때 빈의 id 앞에 앰퍼샌드 기호(&)를 접두사로 붙이면 됩니다. 따라서 id가 myBean인 FactoryBean에 대해 컨테이너에서 getBean("myBean")을 호출하면
FactoryBean의 생성물이 반환되고, getBean("&myBean")을 호출하면
FactoryBean 인스턴스 자체가 반환됩니다.
Bean Definition Inheritance
Annotation-based Container Configuration