메서드 주입
- 룩업 메서드 주입과 메서드 대체 2가지 방법이 있다.
- 이 기능들을 위해 CGLIB의 동적 바이트코드 확장 기능을 사용한다.
룩업 메서드 주입
- 서로 다른 라이프사이클을 가진 bean간의 의존성을 해결하기 위한 방법(싱글턴 - 비싱글턴)
- 싱글턴 bean이 비싱글턴 bean에 의존하는 경우 비싱글턴 bean은 싱글턴이 되어버린다.
- 싱글턴 bean에 ApplicationContextAware 인터페이스를 구현하여 처리한다.
- 비싱글턴 bean의 인스턴스를 반환하는 룩업 메서드를 싱글턴 bean에 선언하여 동작한다.
- 룩업 메서드는 구현 없이 정의만 하므로 구현 클래스를 abstract로 선언한다.
...
public class Singer {
private String lyric = "I played a quick game of chess with the salt and pepper shaker";
public void sing() {
...
}
}
...
public interface DemoBean {
Singer getMySinger();
void doSomething();
}
- 수정자 주입을 통해 의존성(Singer)을 가져오는 StandardLookupDemoBean 클래스
- 이 경우 mySinger는 항상 동일한 인스턴스이다.
...
public class StandardLookupDemoBean implements DemoBean {
private Singer mySinger;
public void setMySinger(Singer mySinger) {
this.mySinger = mySinger;
}
@Override
public Singer getMySinger() {
return this.mySinger;
}
@Override
public void doSomething() {
mySinger.sing();
}
}
- 메서드 주입을 통해 의존성(Singer)을 가져오는 AbstractLookupDemoBean 클래스
- 이 경우 getMySinger()를 통해 반환되는 인스턴스는 항상 다른 인스턴스이다.
- 매번 다른 인스턴스를 생성하기 때무에 성능이 매우 느리다.
- 스프링은 CGLIB를 사용해 동적으로 AbstractLookupDemoBean 클래스의 하위 클래스를 생성한다.
...
public abstract class AbstractLookupDemoBean implements DemoBean {
// lookup 메서드는 파라미터를 받아서는 안되며 의존할 bean을 반환해야 한다.
public abstract Singer getMySinger();
@Override
public void doSomething() {
getMySinger().sing();
}
}
<beans ...>
<bean id="singer"
class="com.apress...Singer"
scope="prototype" />
<bean id="abstractLookupBean"
class="com.apress...AbstractLookupDemoBean">
<!-- lookup 메서드에 대한 구성 추가 -->
<lookup-method name="getMySinger" bean="singer" />
</bean>
<bean id="standardLookupBean"
class="com.apress...StandardLookupDemoBean">
<property name="mySinger" reg="singer" />
</bean>
</beans>
ApplicationContext를 이용한 추상 클래스의 인스턴스 생성은 룩업 메서드 주입을 이용할 경우만 혀용된다.
애노테이션을 이용한 록업 메서드 주입
...
@Component("singer")
@Scope("prototype")
public class Singer {
private String lyric = "I played a quick game of chess with the salt and pepper shaker";
public void sing() {
...
}
}
...
@Component("abstractLookupBean")
public abstract class AbstractLookupDemoBean implements DemoBean {
@Lookup("singer")
public abstract Singer getMySinger() {
return null; // 메서드 내용은 동적으로 생성된 하위 클래스에서 오버라이드 됨
}
@Override
public void doSomething() {
getMySinger().sing();
}
}
...
@Component("standardLookupBean")
public class StandardLookupDemoBean implements DemoBean {
private Singer mySinger;
@Autowired
@Qualifier("singer")
public void setMySinger(Singer mySinger) {
this.mySinger = mySinger;
}
@Override
public Singer getMySinger() {
return this.mySinger;
}
@Override
public void doSomething() {
mySinger.sing();
}
}
<beans ...>
<!-- 애노테이션이 적용된 클래스가 포함된 패키지만 스캔하도록 한다. -->
<context:component-scan base-package="come.apress..." />
</beans>
룩업 메서드 사용 시 주의할 점
- IoC 목적으로만 사용되는 불필요한 정의를 비지니스 인터페이스에 선언하지 않아야 한다.
- 룩업 메서드를 반드시 추상화 할 필요는 없으나 추상화 하는 것이 좋다.