Spring Custom Scope Example
March 10, 2023
Spring provides Scope
interface to create custom scopes. The Scope
interface is a strategy interface that allows for extending the standard scopes "singleton" and "prototype" of BeanFactory
with custom further scopes, registered for a specific key. The Scope
implementations are expected to be thread-safe.
In our example, we will create our custom scope as thread scope. Thread scope means a bean creation and destruction will be limited to a thread life cycle.
Create Custom Scope
Find the custom thread scope implementation class.CustomThreadScope.java
package com.concretepage; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; public class CustomThreadScope implements Scope { CustomThreadLocal customThreadLocal = new CustomThreadLocal(); @SuppressWarnings("rawtypes") @Override public Object get(String str, ObjectFactory objectFactory) { System.out.println("getting object from scope."); @SuppressWarnings("unchecked") Map<String, Object> scope = (Map<String, Object>) customThreadLocal.get(); Object object = scope.get(str); if (object == null) { object = objectFactory.getObject(); scope.put(str, object); } return object; } @Override public String getConversationId() { return null; } @Override public void registerDestructionCallback(String arg0, Runnable arg1) { } @Override public Object remove(String str) { Map<String, Object> scope = (Map<String, Object>) customThreadLocal.get(); return scope.remove(str); } @Override public Object resolveContextualObject(String arg0) { return null; } class CustomThreadLocal extends ThreadLocal { protected Map<String, Object> initialValue() { System.out.println("initialize ThreadLocal"); return new HashMap<String, Object>(); } } }
Register Custom Scope
We need to register our custom scope class with Spring container. We can do it in JavaConfig as well as in application XML.app-conf.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="customThread"> <bean class="com.concretepage.CustomThreadScope"/> </entry> </map> </property> </bean> <bean id="testA" class="com.concretepage.A" scope="customThread" /> </beans>
SpringTest.java
package com.concretepage; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("app-conf.xml"); context.getBean("testA"); } }
getting object from scope. initialize ThreadLocal Bean A is initialized
ConfigurableBeanFactory beanFactory= new DefaultListableBeanFactory(); Scope threadScope= new CustomThreadScope(); beanFactory.registerScope("customThread", threadScope);