Spring Method LookUp Injection
- 프로그래밍/Spring FWK
- 2015. 12. 16. 15:51
Scope "prototype"의 문제
1 2 3 4 5 6 7 | <bean id = "someBean" class = "com.SomeBean" scope="prototype"/> <bean id = "singleBean" class = "com.SingleTone"> <property name="mySomeBean"> <ref bean="someBean"/> </property> </bean> | cs |
Metod LookUp Injection
사용목적
- 생명주기가 다른 두 빈에 대한 작업을 할 때 사용.
- 싱글턴 빈이 비싱글턴 이여야할 참조를 가지고 있어서, 비싱글턴이여야 하는 객체가 싱글톤으로 동작하는 문제해결.
사용방법
- 싱글톤 대상 클래스 A가 구현할 Interface IA
- createB() 등과 같이 신규 인스턴스를 리턴할 메소드 정의. (룩업 메소드 대상)
- 싱글톤 대상 클래스 A
- IA를 구현하여 메소드를 생성한다 (대신 abstract 키워드로 추상메서드로 구현한다)
- bean을 정의할 때 <bean><lookup-method name="createB" bean="beanB"/></bean>
- 비싱글톤 대상 클래스를 B
- bean 정의시 내부 scope="prototype"으로 지정한다.
주의사항 (필수사항은 아니고, 권장사항 이다)
- 룩업 대상 메서드는 인터페이스에 선언하여 상속 받을 것.
- 룩업 대상 메서드를 추상 메서드로 만들 것.
- 성능저하 발생하기 때문에 가급적 안쓰는게 좋음.
Example
설정 및 환경관련 사항
[app-context.xml]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!-- MyPrototype 객체 정의 scope="prototype"으로 지정하여 매번 새로운 인스턴스를 생성하도록 --> <bean id = "prototype" class = "com.java.prototype.MyPrototype" scope="prototype"/> <!-- 일반적인 방식으로 setter 주입을 통해 prototype Bean이 주입된다. --> <bean id = "stdSingleton" class = "com.java.singletonImpl.StandardSingleton"> <property name="mPrototype"> <ref bean="prototype"/> </property> </bean> <!-- lookup-method 주입방식으로 bean이 주입된다. --> <bean id = "absSingleton" class = "com.java.singletonImpl.AbstractSingleton"> <!-- absSingleton bean의 클래스를 런타임 시점에서 Spring이 상속받고 lookup-method name=""으로 지정된 메소드를 구현하여 prototype 객체를 리턴 --> <lookup-method name="getPrototype" bean="prototype"/> </bean> | cs |
1 2 3 4 5 6 7 | package com.java.singleton; import com.java.prototype.MyPrototype; public interface ISingletone { public MyPrototype getPrototype(); } | cs |
[StandardSingleton]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.java.singletonImpl; import com.java.prototype.MyPrototype; import com.java.singleton.ISingletone; public class StandardSingleton implements ISingletone { private MyPrototype mPrototype; public void setmPrototype(MyPrototype mPrototype) { this.mPrototype = mPrototype; } @Override public MyPrototype getPrototype() { return mPrototype; } } | cs |
[AbstractSingleton]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package com.java.singletonImpl; import com.java.prototype.MyPrototype; import com.java.singleton.ISingletone; public abstract class AbstractSingleton implements ISingletone { private MyPrototype mPrototype; public void setmPrototype(MyPrototype mPrototype) { this.mPrototype = mPrototype; } @Override public abstract MyPrototype getPrototype(); } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | package com.java; import org.springframework.context.support.GenericXmlApplicationContext; import org.springframework.util.StopWatch; import com.java.prototype.MyPrototype; import com.java.singleton.ISingletone; import com.java.singletonImpl.AbstractSingleton; import com.java.singletonImpl.StandardSingleton; public class MainClass { public static void main(String[] args) { // ApplicationContext 부트스트랩 GenericXmlApplicationContext appCtx = new GenericXmlApplicationContext(); appCtx.load("classpath:META-INF/spring/app-context.xml"); appCtx.refresh(); ISingletone stdSingle = appCtx.getBean("stdSingleton", StandardSingleton.class); ISingletone absSingle = appCtx.getBean("absSingleton", AbstractSingleton.class); stdSingle.getPrototype(); System.out.println("**********************************************************"); System.out.println("*** setter bean주입 테스트 수행 ***"); System.out.println("*** 예상결과 : 몇 번을 get하더라도 결과는 동일한 인스턴스 리턴 ***"); System.out.println("*** 수행시간 : 빠름 ***"); System.out.println("**********************************************************"); printInfo(stdSingle); System.out.println(""); System.out.println(""); System.out.println("**********************************************************"); System.out.println("*** Method Lookup bean주입 테스트 수행 ***"); System.out.println("*** 예상결과 : bean을 get할 때마다 신규 instance를 리턴하여 다른 객체 리턴***"); System.out.println("*** 수행시간 : 느림 ***"); System.out.println("**********************************************************"); printInfo(absSingle); appCtx.close(); } private static void printInfo(ISingletone single) { MyPrototype proto1 = single.getPrototype(); MyPrototype proto2 = single.getPrototype(); System.out.println("instance1 == instance2 ? " + (proto1 == proto2) ); StopWatch stopWatch = new StopWatch(); stopWatch.start("lookUp Demo"); for (int i = 0; i < 100000; i++) { MyPrototype proto = single.getPrototype(); } stopWatch.stop(); System.out.println("100000 gets took " + stopWatch.getTotalTimeMillis() + "ms"); } } | cs |
<수행결과>
**********************************************************
*** setter bean주입 테스트 수행 ***
*** 예상결과 : 몇 번을 get하더라도 결과는 동일한 인스턴스 리턴 ***
*** 수행시간 : 빠름 ***
**********************************************************
instance1 == instance2 ? true
100000 gets took 2ms
**********************************************************
*** Method Lookup bean주입 테스트 수행 ***
*** 예상결과 : bean을 get할 때마다 신규 instance를 리턴하여 다른 객체 리턴***
*** 수행시간 : 느림 ***
**********************************************************
instance1 == instance2 ? false
100000 gets took 337ms
참고사항
- 자주쓰이지 않음 (거의 쓰이지 않음)
- lookup-method로 지정된 메소드를 갖는 Class가 반드시 abstract일 필요는 없음
- 테스트 해보니 추상클래스가 아니여도 동작
- 지정된 클래스를 cglib가 런타임에서 클래스 변조하여 상속처리 하고 내부 method내용을 override 하는 구조로 동작하는 듯 함.
- cglib 라이브러리가 필요함 (spirng 3.2.x 버젼 부터 cglib spring lib에 내장화하여 필요 없음)
- 어노테이션 방식으로 lookup-method를 지정하는 방식은 책에도 없고 검색에도 없고....의문
다운로드
'프로그래밍 > Spring FWK' 카테고리의 다른 글
Spring Bean Life Cycle (빈 생명주기 관리) (0) | 2015.12.28 |
---|---|
Spring bean 상속 (0) | 2015.12.27 |
Spring Bean Scope 정리 (0) | 2015.12.27 |
Spring Method Replace (replaced-method) (0) | 2015.12.18 |
Spring Non Singletone (0) | 2015.12.14 |
Spring Collection (List, Map, Properties, Set) 주입 (0) | 2015.12.13 |
Spring 다중 applicationContext 중첩사용 (0) | 2015.12.13 |
Spring SpEL을 이용하여 Value세팅하기 (0) | 2015.12.13 |
이 글을 공유하기