The Spring Custom Thread Scope Example show you how to create and implement a custom scope for for creating your own requirements. The need to create a Custom Scope actually depends on the problem at hand. To understand we will create a SimpleThreadScope. It implements the Scope interface which allows us to add, remove and specify a special callback method to manage scope lifecycle.
Other interesting posts you may like
Creating a Custom Scope
One of the first things to consider when implementing a custom Scope class is how you will store and manage the scoped objects and destruction callbacks. In this Spring Custom Thread Scope Example we create a SimpleThreadScope so we store scoped objects in a Map of ThreadLocal instance. SimpleThreadScope has a short lived scope which we can manage and manually clear the scope using an additional clear() method.
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 |
package com.javabycode.spring.core.scope; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; import org.springframework.core.NamedThreadLocal; import java.util.HashMap; import java.util.Map; public class SimpleThreadScope implements Scope { private final ThreadLocal<Map<String, Object>> threadScope = new NamedThreadLocal<Map<String, Object>>(SimpleThreadScope.class.getName()) { @Override protected Map<String, Object> initialValue() { return new HashMap<String, Object>(); } }; @Override public Object get(String name, ObjectFactory<?> objectFactory) { Map<String, Object> scope = this.threadScope.get(); Object object = scope.get(name); if (object == null) { object = objectFactory.getObject(); scope.put(name, object); } return object; } @Override public Object remove(String name) { Map<String, Object> scope = this.threadScope.get(); return scope.remove(name); } @Override public void registerDestructionCallback(String name, Runnable callback) { } @Override public Object resolveContextualObject(String key) { return null; } @Override public String getConversationId() { return Thread.currentThread().getName(); } public void clear(){ Map<String, Object> scope = this.threadScope.get(); scope.clear(); } } |
Create Spring bean
We create a simple bean named Book for testing spring bean scope
Book.java
1 2 3 4 5 6 7 8 |
package com.javabycode.spring.core.scope; public class Book { public Book() { System.out.println("Book initialized"); } } |
Configuring Custom Scope
First we create a bean definition of our custom scope bean and assign it with an id.
1 |
<bean id="thread" class="com.javabycode.spring.core.scope.SimpleThreadScope"/> |
Next we registered our custom scope with the Spring IoC container using CustomScopeConfigurer and setting the scopes property and initialize it with a map containing a reference to our custom SimpleThreadScope bean together with a key. This key is used to register the custom scope.
1 2 3 4 5 6 7 |
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="thread" value-ref="thread"/> </map> </property> </bean> |
Finally we configure the Book bean with our custom thread scope.
1 |
<bean class="com.javabycode.spring.core.scope.Book" scope="thread"/> |
In short, we have the completed spring configuration file like below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="thread" class="com.javabycode.spring.core.scope.SimpleThreadScope"/> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="thread" value-ref="thread"/> </map> </property> </bean> <bean class="com.javabycode.spring.core.scope.Book" scope="thread"/> </beans> |
Demo Custom Scope
In this Spring Custom Thread Scope Example, we create the main class which test if the retrieved bean is the same as the subsequent.
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 |
package com.javabycode.spring.core.scope; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MySpringApplication { public static void main(String... args) throws InterruptedException { ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); System.out.println("ApplicationContext initialized"); System.out.println("Retrieve 'Book' instance"); Book book1 = context.getBean(Book.class); System.out.println("Retrieve 'Book' instance again"); Book book2 = context.getBean(Book.class); System.out.println("Book1 == Book2: " + (book1 == book2)); System.out.println("Clear thread scope"); SimpleThreadScope threadScope = context.getBean(SimpleThreadScope.class); threadScope.clear();//Purge the custom ThreadScope scope System.out.println("Retrieve 'Book' instance"); Book book3 = context.getBean(Book.class); System.out.println("Retrieve 'Book' instance again"); Book book4 = context.getBean(Book.class); System.out.println("Book3 == Book4: " + (book3 == book4)); } } |
Running the main above and output is printed like below
As you see in the output, the instance of Book is created only when the instance does not exist in the SimpleThreadScope bean.
That’s all on the Spring Custom Thread Scope Example.
References
Spring Custom Scope Doc
Download complete source code, click link below
spring-custom-scope-example.zip (301 downloads)