自定义Scope实现每个线程持有一个bean实例

简介: 自定义Scope实现每个线程持有一个bean实例

# 自定义Scope-每个线程获取到的Bean实例是同一个



一、流程:


  1. 实现Scope接口
  2. 将步骤1的Scope对象通过BeanFactoryPostProcessor注册到容器中
  3. 设置Bean的Scope为自定义的Scope
  4. 使用时需要从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中获取,直接注入似乎无效


测试获取beanTestThreadBean,验证是否是每个线程所持有的对象都不一样,但是同一个线程重复获取的都是同一个对象。

/**
 * @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次,且每次都是不同的线程进行的实例化



image.png

每个线程获取到的对象都不一样,但是同一个线程多次获取的都是同一个对象


image.png


# Next

  • 其他Scope的实现,如session
  • 必须通过application获取bean才能实现这样的效果?
相关文章
|
2月前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
220 0
|
7月前
|
Java 数据库连接 调度
面试题:用过线程池吗?如何自定义线程池?线程池的参数?
字节跳动面试题:用过线程池吗?如何自定义线程池?线程池的参数?
103 0
|
16天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
27 1
|
7月前
|
安全 Java Spring
Spring框架中的单例Bean是线程安全的吗?
Spring框架中的单例Bean是线程安全的吗?
91 1
|
4月前
|
存储 Java 开发者
HashMap线程安全问题大揭秘:ConcurrentHashMap、自定义同步,一文让你彻底解锁!
【8月更文挑战第24天】HashMap是Java集合框架中不可或缺的一部分,以其高效的键值对存储和快速访问能力广受开发者欢迎。本文深入探讨了HashMap在JDK 1.8后的底层结构——数组+链表+红黑树混合模式,这种设计既利用了数组的快速定位优势,又通过链表和红黑树有效解决了哈希冲突问题。数组作为基石,每个元素包含一个Node节点,通过next指针形成链表;当链表长度过长时,采用红黑树进行优化,显著提升性能。此外,还介绍了HashMap的扩容机制,确保即使在数据量增大时也能保持高效运作。通过示例代码展示如何使用HashMap进行基本操作,帮助理解其实现原理及应用场景。
66 1
|
5月前
|
Java Spring 容器
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
254 3
|
4月前
|
Java UED
基于SpringBoot自定义线程池实现多线程执行方法,以及多线程之间的协调和同步
这篇文章介绍了在SpringBoot项目中如何自定义线程池来实现多线程执行方法,并探讨了多线程之间的协调和同步问题,提供了相关的示例代码。
1186 0
|
5月前
|
Java
不自定义异步方法的线程池默认使用SimpleAsyncTaskExecutor
不自定义异步方法的线程池默认使用SimpleAsyncTaskExecutor
|
6月前
|
Java
死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`
【6月更文挑战第20天】死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`volatile`保证变量的可见性和部分原子性,确保多线程环境中值的即时更新。与`synchronized`相比,`volatile`作用于单个变量,不保证原子操作,同步范围有限,但开销较小。`synchronized`提供更全面的内存语义,保证原子性和可见性,适用于复杂并发控制。
48 3
|
6月前
|
Java Apache Spring
面试官:如何自定义一个工厂类给线程池命名,我:现场手撕吗?
【6月更文挑战第3天】面试官:如何自定义一个工厂类给线程池命名,我:现场手撕吗?
41 0