이전 글에 보시면 스프링 레퍼런스에서 커스텀 스코프의 예제로 Thread scope를 제시하고 있는 것을 알 수 있습니다. 물론, 구현은 해놓지 않았습니다.
커스텀 스코프의 예제로 무엇을 구현해야 하는 저에게 참 좋은 조언이 되었습니다.
스프링에는 총 다 섯가지의 빈 스코프가 존재합니다.
지금 구현해 볼 스코프는 쓰레드(Thread)별로 빈 인스턴스를 생성하는 쓰레드 스코프 입니다.
하나의 쓰레드에서 특정 빈 인스턴스를 생성했고, 동시에 다른 쓰레드에서 같은 빈 인스턴스를 요청하는 경우 새로운 빈 인스턴스를 생성하게 하는 것 입니다. 하지만 같은 쓰레드에서 같은 빈 인스턴스를 요청하는 경우에는 기존에 생성했던 빈 인스턴스를 돌려줍니다.
혹시나 이전 글을 못 보시고 이 글을 관심있게 보시는 분들은 이전 글을 한 번 보시는게 도움이 될 것 같습니다.
쓰레드 스코프는 스프링 2.0에서 추가된 request와 session 스코프의 구현 방식으로 구현해봤습니다.
기본적인 구현 모습은 다음과 같습니다.
Scope 인터페이스를 구현해 ThreadScope 클래스를 작성합니다.
ThreadScope는 Scope 인터페이스를 통해서 BeanFactory에서 호출되는 get()과 remove(), registerDestructionCallback(), getConversationId() 메소드를 구현하고 있습니다.
ThreadContextAttributesHolder 클래스는 실제 빈 인스턴스를 저장하는 클래스와 ThreadScope과의 다리 역할을 해줍니다. ThreadScope에서는 ThreadContextAttributesHolder를 통해서 실제 빈 인스턴스를 저장해 놓은 클래스를 받게 됩니다.
ThreadContextAttributes 인터페이스는 실제 빈 인스턴스를 저장하는 클래스의 인터페이스로 빈 인스턴스를 맵에 저장하는 오퍼레이션과 맵에 관련된 오퍼레이션을 갖고 있습니다.
ThreadContextAttributesImpl은 ThreadContextAttributes 인터페이스를 직접 구현한 클래스입니다.
테스트 클래스에서 쓰레드를 두 개 생성해서 동시에 두 개의 쓰레드에서 빈 인스턴스를 각각 생성했는지 확인해보겠습니다. 테스트 클래스에서 쓰레드를 생성하는 메소드를 두 번 호출합니다.
실제로 빈을 받아오는 작업을 할 쓰레드 클래스를 작성합니다.
테스트를 위해서 thread 스코프의 빈 하나와 signleton 스코프의 빈을 하나를 각 각 받아옵니다. 또 한 thread scope 내에서는 같은 빈을 받아 오는지 확인 하기 위해 thread scope의 같은 빈을 두 번 불러옵니다.
마지막으로 설정 파일을 통해서 thread scope을 선언해주고, thread와 singleton scope의 빈을 각 각 선언해줍니다.
테스트의 실행 결과를 확인해보면, 같은 쓰레드에서 호출한 thread scope의 빈은 같은 빈 인스턴스를 받아 온 것을 확인해볼 수 있으며, 다른 쓰레드에서 호출한 빈 인스턴스는 다른 빈 인스턴스를 받아 온 것을 알 수 있습니다.
우여곡절 끝에 thread scope을 만들었습니다.
다음 글에서 실제 소스 코드를 확인해보겠습니다.
커스텀 스코프의 예제로 무엇을 구현해야 하는 저에게 참 좋은 조언이 되었습니다.
스프링에는 총 다 섯가지의 빈 스코프가 존재합니다.
지금 구현해 볼 스코프는 쓰레드(Thread)별로 빈 인스턴스를 생성하는 쓰레드 스코프 입니다.
하나의 쓰레드에서 특정 빈 인스턴스를 생성했고, 동시에 다른 쓰레드에서 같은 빈 인스턴스를 요청하는 경우 새로운 빈 인스턴스를 생성하게 하는 것 입니다. 하지만 같은 쓰레드에서 같은 빈 인스턴스를 요청하는 경우에는 기존에 생성했던 빈 인스턴스를 돌려줍니다.
혹시나 이전 글을 못 보시고 이 글을 관심있게 보시는 분들은 이전 글을 한 번 보시는게 도움이 될 것 같습니다.
쓰레드 스코프는 스프링 2.0에서 추가된 request와 session 스코프의 구현 방식으로 구현해봤습니다.
기본적인 구현 모습은 다음과 같습니다.
Scope 인터페이스를 구현해 ThreadScope 클래스를 작성합니다.
ThreadScope는 Scope 인터페이스를 통해서 BeanFactory에서 호출되는 get()과 remove(), registerDestructionCallback(), getConversationId() 메소드를 구현하고 있습니다.
ThreadContextAttributesHolder 클래스는 실제 빈 인스턴스를 저장하는 클래스와 ThreadScope과의 다리 역할을 해줍니다. ThreadScope에서는 ThreadContextAttributesHolder를 통해서 실제 빈 인스턴스를 저장해 놓은 클래스를 받게 됩니다.
ThreadContextAttributes 인터페이스는 실제 빈 인스턴스를 저장하는 클래스의 인터페이스로 빈 인스턴스를 맵에 저장하는 오퍼레이션과 맵에 관련된 오퍼레이션을 갖고 있습니다.
ThreadContextAttributesImpl은 ThreadContextAttributes 인터페이스를 직접 구현한 클래스입니다.
테스트 클래스에서 쓰레드를 두 개 생성해서 동시에 두 개의 쓰레드에서 빈 인스턴스를 각각 생성했는지 확인해보겠습니다. 테스트 클래스에서 쓰레드를 생성하는 메소드를 두 번 호출합니다.
public class ThreadScopeTest extends AbstractDependencyInjectionSpringContextTests {
private void runThread(){
ThreadScopeTestKit thread = new ThreadScopeTestKit(applicationContext);
thread.start();
}
public void testOnlyOneThreadTestWithThreadScopeOne(){
runThread();
runThread();
}
}
private void runThread(){
ThreadScopeTestKit thread = new ThreadScopeTestKit(applicationContext);
thread.start();
}
public void testOnlyOneThreadTestWithThreadScopeOne(){
runThread();
runThread();
}
}
실제로 빈을 받아오는 작업을 할 쓰레드 클래스를 작성합니다.
public class ThreadScopeTestKit extends Thread {
private ApplicationContext applicationContext;
public ThreadScopeTestKit(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void run() {
System.out.println("Test Thread " + this.toString() + " Start.");
ThreadScopedBean threadScopeBeanOne =
(ThreadScopedBean) applicationContext.getBean("threadScopeBean");
System.out.println("[ThreadScopeBeanOne : " + threadScopeBeanOne.toString()+ "]");
ThreadScopedBean threadScopeBeanTwo =
(ThreadScopedBean) applicationContext.getBean("threadScopeBean");
System.out.println("[ThreadScopeBeanTwo : " + threadScopeBeanTwo.toString()+ "]");
SingletonScopeBean singletonScopeBean =
(SingletonScopeBean)applicationContext.getBean("singletonScopeBean");
System.out.println("[SingletonBean : " + singletonScopeBean.toString() + "]");
System.out.println(this.toString() + " Thread End.");
}
}
private ApplicationContext applicationContext;
public ThreadScopeTestKit(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void run() {
System.out.println("Test Thread " + this.toString() + " Start.");
ThreadScopedBean threadScopeBeanOne =
(ThreadScopedBean) applicationContext.getBean("threadScopeBean");
System.out.println("[ThreadScopeBeanOne : " + threadScopeBeanOne.toString()+ "]");
ThreadScopedBean threadScopeBeanTwo =
(ThreadScopedBean) applicationContext.getBean("threadScopeBean");
System.out.println("[ThreadScopeBeanTwo : " + threadScopeBeanTwo.toString()+ "]");
SingletonScopeBean singletonScopeBean =
(SingletonScopeBean)applicationContext.getBean("singletonScopeBean");
System.out.println("[SingletonBean : " + singletonScopeBean.toString() + "]");
System.out.println(this.toString() + " Thread End.");
}
}
테스트를 위해서 thread 스코프의 빈 하나와 signleton 스코프의 빈을 하나를 각 각 받아옵니다. 또 한 thread scope 내에서는 같은 빈을 받아 오는지 확인 하기 위해 thread scope의 같은 빈을 두 번 불러옵니다.
마지막으로 설정 파일을 통해서 thread scope을 선언해주고, thread와 singleton scope의 빈을 각 각 선언해줍니다.
<bean id="threadScopeBean"
class="net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean"
scope="thread"
p:name="threadBean">
<aop:scoped-proxy/>
</bean>
<bean id="singletonScopeBean" class="net.agilejava.jedi.beanScope.customScope.bean.SingletonScopeBean"
p:name="singetonBean" />
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread">
<bean class="net.agilejava.jedi.beanScope.customScope.scope.ThreadScope" />
</entry>
</map>
</property>
</bean>
class="net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean"
scope="thread"
p:name="threadBean">
<aop:scoped-proxy/>
</bean>
<bean id="singletonScopeBean" class="net.agilejava.jedi.beanScope.customScope.bean.SingletonScopeBean"
p:name="singetonBean" />
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread">
<bean class="net.agilejava.jedi.beanScope.customScope.scope.ThreadScope" />
</entry>
</map>
</property>
</bean>
테스트의 실행 결과를 확인해보면, 같은 쓰레드에서 호출한 thread scope의 빈은 같은 빈 인스턴스를 받아 온 것을 확인해볼 수 있으며, 다른 쓰레드에서 호출한 빈 인스턴스는 다른 빈 인스턴스를 받아 온 것을 알 수 있습니다.
Test Thread Thread[Thread-0,5,main] Start.
[ThreadScopeBeanOne : net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean@c980c9, Bean name + threadBean]
[ThreadScopeBeanTwo : net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean@c980c9, Bean name + threadBean]
[SingletonBean : net.agilejava.jedi.beanScope.customScope.bean.SingletonScopeBean@12611a7]
Thread[Thread-0,5,main] Thread End.
Test Thread Thread[Thread-1,5,main] Start.
[ThreadScopeBeanOne : net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean@51052d, Bean name + threadBean]
[ThreadScopeBeanTwo : net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean@51052d, Bean name + threadBean]
[SingletonBean : net.agilejava.jedi.beanScope.customScope.bean.SingletonScopeBean@12611a7]
Thread[Thread-1,5,main] Thread End.
[ThreadScopeBeanOne : net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean@c980c9, Bean name + threadBean]
[ThreadScopeBeanTwo : net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean@c980c9, Bean name + threadBean]
[SingletonBean : net.agilejava.jedi.beanScope.customScope.bean.SingletonScopeBean@12611a7]
Thread[Thread-0,5,main] Thread End.
Test Thread Thread[Thread-1,5,main] Start.
[ThreadScopeBeanOne : net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean@51052d, Bean name + threadBean]
[ThreadScopeBeanTwo : net.agilejava.jedi.beanScope.customScope.bean.ThreadScopedBean@51052d, Bean name + threadBean]
[SingletonBean : net.agilejava.jedi.beanScope.customScope.bean.SingletonScopeBean@12611a7]
Thread[Thread-1,5,main] Thread End.
우여곡절 끝에 thread scope을 만들었습니다.
다음 글에서 실제 소스 코드를 확인해보겠습니다.

Prev

Rss Feed