singleton
注意事项:
- 默认为singleton,即为单例。
- 整个应用共享,需考虑线程安全。
配置方式:
<bean id="" class="" scope="singleton" >或<bean id="" class="" >
prototype
注意事项:
- 需要在scope属性中指定prototype,多例。
- 每次获取时需重新加载。若实例较大,创建时间长、影响系统性能。
配置方式:
<bean id="" class="" scope="prototype">
以下为spring web容器环境中才有
request
注意事项:
- 需要在scope属性中指定request,每次请求创建。
- 由WebApplicationContext接口提供支持。
配置方式:
<bean id="" class="" scope="prototype">
session
注意事项:
- 需要在scope属性中指定session,每个session。
- 由WebApplicationContext接口提供支持。
- session级别共享
配置方式:
<bean id="" class="" scope="session">
application
注意事项:
- 需要在scope属性中指定application,每次请求创建。
- 由WebApplicationContext接口提供支持。
- 一般情况下与singleton相同,一个应用程序可以创建多个spring容器,scope为application时,同名bean一个。
配置方式:
<bean id="" class="" scope="application">
自定义scope
共三步
一、实现Scope接口
package org.springframework.beans.factory.config;
import org.springframework.beans.factory.ObjectFactory;
public interface Scope {
/**
* 返回当前作用域中name所对应的bean对象
* @param name 需要检索的bean名称
* @param objectFactory 没找到的情况下,创建该对象
* @return 找到的对象
*/
Object get(String name, ObjectFactory<?> objectFactory);
/**
* 移除检索到的name对象
* @param name 需要检索的bean名称
* @return 返回删除的对象
*/
Object remove(String name);
/**
* 回调函数,用于销毁响应对象,
* 由Spring容器注册相应的销毁回调
* @param name bean名称
* @param callback 回调函数
*/
void registerDestructionCallback(String name, Runnable callback);
/**
* 解析上下文数据
* @param key 上下文键
* @return 对应对象,若没找到,返回null
*/
Object resolveContextualObject(String key);
/**
* 会话标识
* @return 返回字符串会话标识
*/
String getConversationId();
}
二、自定义scope注册到容器
方法声明片段如下:package org.springframework.beans.factory.config;
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
//-------------一些代码--------------------------------
/**
* 向容器注册作用域
* @param scopeName 作用域名称
* @param scope 作用域对象
*/
void registerScope(String scopeName, Scope scope);
//-------------一些代码--------------------------------
}
三、使用自定义scope
示例
ThreadScope
main\java\com\shimeath\test\demo1\ThreadScope.java
package com.shimeath.test.demo1;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.lang.Nullable;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* TheadScope通过实现Scope接口,自定义scope
* 作用域为一个线程
*/
public class ThreadScope implements Scope {
/**
* 作用域名称为thread,定义bean时可以给scope使用
*/
public static final String THREAD_SCOPE = "thread";
private ThreadLocal<Map<String, Object>> beanMap = new ThreadLocal(){
@Override
protected Object initialValue() {
return new HashMap<>();
}
};
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Object bean = beanMap.get().get(name);
if(Objects.isNull(bean)){
bean = objectFactory.getObject();
beanMap.get().put(name,bean);
}
return bean;
}
@Nullable
@Override
public Object remove(String name) {
return this.beanMap.get().remove(name);
}
/**
* 回调函数,作用域结束时调用,输出name
* @param name
* @param runnable
*/
@Override
public void registerDestructionCallback(String name, Runnable runnable) {
System.out.println(name);
}
@Override
public Object resolveContextualObject(String s) {
return null;
}
@Override
public String getConversationId() {
return Thread.currentThread().getName();
}
}
BeanScopeModel
main\java\com\shimeath\test\demo1\BeanScopeModel.java
package com.shimeath.test.demo1;
public class BeanScopeModel {
/**
* 输出当前线程信息
* @param beanScope
*/
public BeanScopeModel(String beanScope){
System.out.println(String.format("线程:%s,create BeanScopeModel,{scope=%s},{this=%s}", Thread.currentThread(), beanScope,this));
}
}
bean配置
main\resources\bean.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="threadBean" class="com.shimeath.test.demo1.BeanScopeModel" scope="thread">
<constructor-arg index="0" value="thread"/>
</bean>
</beans>
测试用例
package com.shimeath.test.demo1;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
public class Client {
public static void main(String[] args) throws InterruptedException {
//导入配置文件
String beanXml = "classpath:bean.xml";
//创建容器,加载bean配置文件
ClassPathXmlApplicationContext context;
context = new ClassPathXmlApplicationContext(beanXml);
context.refresh();
context.getBeanFactory().registerScope(ThreadScope.THREAD_SCOPE, new ThreadScope());
for (int i = 0; i < 2; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread() + "," + context.getBean("threadBean"));
System.out.println(Thread.currentThread() + "," + context.getBean("threadBean"));
}).start();
TimeUnit.SECONDS.sleep(1);
}
}
输出如下
线程:Thread[Thread-1,5,main],create BeanScopeModel,{scope=thread},{this=com.shimeath.test.demo1.BeanScopeModel@770a131f}
Thread[Thread-1,5,main],com.shimeath.test.demo1.BeanScopeModel@770a131f
Thread[Thread-1,5,main],com.shimeath.test.demo1.BeanScopeModel@770a131f
线程:Thread[Thread-2,5,main],create BeanScopeModel,{scope=thread},{this=com.shimeath.test.demo1.BeanScopeModel@a38feba}
Thread[Thread-2,5,main],com.shimeath.test.demo1.BeanScopeModel@a38feba
Thread[Thread-2,5,main],com.shimeath.test.demo1.BeanScopeModel@a38feba
总结
以上结果可以看出,自定义scope生效。不同的线程中的bean均为不同的bean