# 自定义Scope-每个线程获取到的Bean实例是同一个
一、流程:
- 实现Scope接口
- 将步骤1的Scope对象通过BeanFactoryPostProcessor注册到容器中
- 设置Bean的Scope为自定义的Scope
- 使用时需要从ApplicationContext中获取,直接注入似乎无效
二、详细流程:
1.实现Scope接口
2.将步骤1的Scope对象通过BeanFactoryPostProcessor注册到容器中
/**
* 自定义Bean的Scope
* target: 每个线程获取到的Bean实例都是同一个
*
* @author ft
* @date 2021/1/28
*/
@Component(ThreadScope.SCOPE)
public class ThreadScope implements Scope, BeanFactoryPostProcessor {
/**
* 线程本地变量持有当前线程获取到的Bean实例
*/
private static final ThreadLocal<Object> THREAD_LOCAL_BEAN = new ThreadLocal<>();
/**
* 自定义的Scope的名称
*/
public static final String SCOPE = "threadLocal";
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Object o = THREAD_LOCAL_BEAN.get();
if (o == null) {
THREAD_LOCAL_BEAN.set(objectFactory.getObject());
}
return THREAD_LOCAL_BEAN.get();
}
@Override
public Object remove(String name) {
Object o = THREAD_LOCAL_BEAN.get();
THREAD_LOCAL_BEAN.remove();
return o;
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
}
@Override
public Object resolveContextualObject(String key) {
return null;
}
@Override
public String getConversationId() {
return null;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 将自定义的Scope注册到容器中
beanFactory.registerScope(ThreadScope.SCOPE, this);
}
}
3.设置Bean的Scope为自定义的Scope
/**
* Scope为每个线程持有一个对象
*
* @author ft
* @date 2021/1/28
*/
@Scope(ThreadScope.SCOPE)
@Component
@Slf4j
public class TestThreadBean {
/**
* 构造方法,当进行了实例构建可以看到日志
*/
public TestThreadBean() {
log.info(".");
}
public void sayThing() {
log.info("-");
}
}
4.使用时需要从ApplicationContext中获取,直接注入似乎无效
测试获取bean
TestThreadBean,验证是否是每个线程所持有的对象都不一样,但是同一个线程重复获取的都是同一个对象。
/**
* @author ft
* @date 2021/1/28
*/
@Slf4j
@Component
public class ThreadScopeTest implements ApplicationRunner {
@Autowired
private ApplicationContext applicationContext;
@Override
public void run(ApplicationArguments args) throws Exception {
// 开启10个线程
for (int i = 0; i < 10; i++) {
new Thread(() -> {
// 从容器中获取TestThreadBean实例
TestThreadBean bean1 = applicationContext.getBean(TestThreadBean.class);
log.info("第一次获取:{}", bean1);
// 同一个线程第二次从容器中获取TestThreadBean实例
TestThreadBean bean2 = applicationContext.getBean(TestThreadBean.class);
log.info("第二次获取:{}", bean2);
}, "scope-test-" + i).start();
}
}
}
5. 测试结果
- 实例化了10次,且每次都是不同的线程进行的实例化
图片.png
- 每个线程获取到的对象都不一样,但是同一个线程多次获取的都是同一个对象
图片.png
# Next
- 其他Scope的实现,如
session - 必须通过application获取bean才能实现这样的效果?












网友评论