동일한 scope 의 bean 에 의존성을 가질 때, 일반적으로 bean 의 속성에 의존성을 추가하여 처리한다. 예를 들어 singleton bean 이 prototype bean 을 의존한다면, 컨테이너는 singleton bean 을 단 한번 생성하므로 필요할 때마다 prototype bean 을 제공할 수 없다.
아래는 ApplicationContextAware 를 구현하여 singleton bean 에서 prototype bean 의 새 인스턴스를 요청하는 예제이다.
package fiona.apple; // Spring-API imports import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class CommandManager implements ApplicationContextAware { private ApplicationContext applicationContext; public Object process(Map commandState) { Command command = createCommand(); command.setState(commandState); return command.execute(); } protected Command createCommand() { // Spring API getBean() 를 의존하고 있다. return this.applicationContext.getBean("command", Command.class); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } } | cs |
위 예제에서 컨테이너가 createCommand() 메서드의 구현을 동적으로 재정의한다는 것을 알 수 있다. Spinrg Framework 와 비지니스 코드와 결합되어 있으므로 바람직하지 않지만, 컨테이너의 lookup 메소드 주입을 사용하면 이를 해결할 수 있다.
lookup 메소드 주입은 bean 의 메소드를 재정의하여, 다른 이름의 bean 으로 대체시키는 컨테이너의 기능이다. Spring Framework 는 메소드를 재정의하는 서브 클래스를 동적으로 생성하기 위해 CGLIB 라이브러리의 바이트 코드 생성을 사용한다. 이 때 서브 클래스화 할 클래스와 재정의 할 메소드는 final 이 될 수 없다. lookup 메소드 주입은 factory 메소드나 @Bean 에서는 작동하지 않는다.
주입될 메소드는 다음의 형식으로 작성한다.
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
추상 메소드라면 동적으로 생성된 서브 클래스는 이 메소드를 구현하고, 그렇지 않으면 동적으로 생성된 서브 클래스가 원래 클래스에 정의된 메서드를 재정의한다. 아래 예제에서는 lookup 메소드 주입으로 Spring 과 결합되어 있지 않다.
package fiona.apple; // no more Spring imports! public abstract class CommandManager { public Object process(Object commandState) { Command command = createCommand(); command.setState(commandState); return command.execute(); } protected abstract Command createCommand(); } | cs |
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype"> <!-- 의존성 주입 --> </bean> <bean id="commandManager" class="fiona.apple.CommandManager"> <lookup-method name="createCommand" bean="myCommand"/> </bean> | cs |
commandManager bean 은 myCommand bean 의 새 인스턴스가 필요할 때마다 createCommand() 를 호출한다.
또는 어노테이션 컴포넌트 모델에서 @Lookup 어노테이션을 통해 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(); // or // @Lookup // protected abstract MyCommand createCommand(); } | cs |
WRITTEN BY
- 손가락귀신
정신 못차리면, 벌 받는다.