Spring series 8: scope of bean s

Posted by shaundunne on Tue, 01 Feb 2022 10:13:37 +0100

Content of this article

  1. Meaning of bean definition information
  2. This paper introduces the scope of six kinds of bean s

Meaning of bean definition information

Spring distinguishes the concept of class, class definition information and class instance object? It's not easy to understand. Take fried rice ordered in a restaurant as an example.

Class: it's equivalent to seeing the dish fried rice on the menu.

Class definition information: it is equivalent to the cooking method of fried rice. There is only one cooking method

Class instance object: equivalent to one fried rice fried according to the above cooking method, which can be fried into multiple portions.

If you create a class definition information in the spring container, you can create a class instance object based on this definition information. This understanding is very important. Spring can not only control various dependencies and configuration values in the bean object, but also control the scope of the bean amount.

This paper introduces the scope of six kinds of bean s

The Spring Framework supports the scope of six bean s, four of which are only available in the ApplicationContext of web type. See the following table for details

Scope describe
singleton (default) limit a single bean definition to a single object instance of each Spring IoC container.
prototype Limit a single bean definition to any number of object instances
request Limit a single bean definition to the life cycle of a single HTTP request. That is, each HTTP request has its own bean instance, which is created after the definition of a single bean. Valid only in ApplicationContext of web type.
session Limit a single bean definition to the life cycle of an HTTP session. Valid only in ApplicationContext of web type.
application Define a single bean as the lifecycle of ServletContext. Valid only in ApplicationContext of web type.
websocket Define a single bean as the life cycle of WebSocket. Valid only in ApplicationContext of web type.

Starting with Spring 3.0, thread scope is available, but it is not registered by default. If you are interested in SimpleThreadScope, you can see the following custom scope in detail.

singleton

Only a shared instance of a singleton bean is managed, and all requests for a bean with one or more ID s that match the bean definition cause the Spring container to return a specific bean instance. "Scorpion Baba is the only one". Note that it is in an IoC container.

prototype

Each time the container creates a new bean instance under the prototype scope. Generally speaking, prototypes are suitable for stateful beans and singletons are suitable for stateless beans.

The following configuration section specifies that the scope of the bean is prototype.

<bean id="accountService" class="x.y.z.AccountService" scope="prototype"/>

Compared with other scopes, Spring does not manage the full life cycle of prototype beans. The container instantiates, configures and otherwise assembles the prototype object and passes it to the client, which is managed by the client. The bean lifecycle is described later.

request, session, application, webSocket

These four scopes used in the context of web applications will not be discussed for the time being, but will be left to spring mvc later.

Custom scope and usage

How to customize?

You can do this by implementing org springframework. beans. factory. config. Scope custom scope. The scope interface has four ways to get objects from the scope, remove them from the scope, and let them be destroyed.

package org.springframework.beans.factory.config;
public interface Scope {
    // Returns an object with a given name from the underlying scope
	Object get(String name, ObjectFactory<?> objectFactory);
    // Deletes an object with a given from the underlying scope
    Object remove(String name);
    // Registers the callback to be executed when the specified object is destroyed in the scope
    void registerDestructionCallback(String name, Runnable callback);
	// ellipsis
}

While the iron is hot, go directly to the source code of SimpleThreadScope to analyze how the thread level scope is implemented.

package org.springframework.context.support;

public class SimpleThreadScope implements Scope {

	private static final Log logger = LogFactory.getLog(SimpleThreadScope.class);
	// 1 bean is stored in ThreadLocal and bound to the current thread 
	private final ThreadLocal<Map<String, Object>> threadScope =
			new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") {
				@Override
				protected Map<String, Object> initialValue() {
					return new HashMap<>();
				}
			};

    // 2. Check ThreadLocal. If there is a corresponding bean, it will be returned directly. If there is no bean, it will be created and put into ThreadLocal. After returning
	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
		Map<String, Object> scope = this.threadScope.get();
		Object scopedObject = scope.get(name);
		if (scopedObject == null) {
			scopedObject = objectFactory.getObject();
			scope.put(name, scopedObject);
		}
		return scopedObject;
	}

    // 3 remove bean from ThreadLocal
	@Override
	@Nullable
	public Object remove(String name) {
		Map<String, Object> scope = this.threadScope.get();
		return scope.remove(name);
	}

    // 4. Destroy callback
	@Override
	public void registerDestructionCallback(String name, Runnable callback) {
		logger.warn("SimpleThreadScope does not support destruction callbacks. " +
				"Consider using RequestScope in a web environment.");
	}

	@Override
	@Nullable
	public Object resolveContextualObject(String key) {
		return null;
	}

	@Override
	public String getConversationId() {
		return Thread.currentThread().getName();
	}

}

How to use?

  1. First inject the custom scope into the container

    Registration by encoding: the ConfigurableBeanFactory interface provides registerScope to register custom scopes.

    Scope threadScope = new SimpleThreadScope();
    beanFactory.registerScope("thread", threadScope);
    

    Registration in configuration file mode: use CustomScopeConfigurer to register declaratively

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
            <property name="scopes">
                <map>
                    <entry key="thread">
                        <bean class="org.springframework.context.support.SimpleThreadScope"/>
                    </entry>
                </map>
            </property>
        </bean>
    </beans>    
    
  2. Used in bean configuration

    Use the same way as ordinary scope.

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
            <property name="scopes">
                <map>
                    <entry key="thread">
                        <bean class="org.springframework.context.support.SimpleThreadScope"/>
                    </entry>
                </map>
            </property>
        </bean>
    
        <bean id="thing2" class="x.y.Thing2" scope="thread">
            <property name="name" value="Rick"/>
            <aop:scoped-proxy/>
        </bean>
    
        <bean id="thing1" class="x.y.Thing1">
            <property name="thing2" ref="thing2"/>
        </bean>
    
    </beans>
    

summary

This article describes the seven scopes in Spring and how to customize and use them. The next article introduces annotation based Spring container configuration.

Knowledge sharing, please indicate the source of reprint. There is no order in learning, and the one who reaches is the first!

Topics: Java