Singleton与Prototype

Posted asleaf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Singleton与Prototype相关的知识,希望对你有一定的参考价值。

Singleton Bean

对于singleton bean来说,IoC容器只管理一个singleton bean的一个共享实例,所有匹配该bean定义的请求都会让IoC容器返回一个特定的bean实例。

也就是说,当定义一个bean是singleton范围时,IoC容器仅创建一个由该bean定义的对象实例。该单个实例储存在缓存中,对该bean所有后续请求和引用都将返回缓存中的对象实例。

在Spring IoC容器中,singleton bean是默认创建bean的方式,可以更好地重用对象,节省开销。

Prototype Bean

对于prototype bean来说,IoC容器每次处理该bean的请求时都会创建一个新的bean实例。

从某种意义上来说,IoC容器在prototype bean上的作用等同于Java的new操作符,所有实例的生命周期管理都必须由客户端处理。

多线程下的Singleton与Prototype

多线程情况下如果需要每次调用都生成一个实例,可以设置scope为prototype。

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Task implements Runnable { 
    @Override
    public void run() {
    }
}

但是,如果singleton bean依赖prototype bean,通过依赖注入方式,prototype bean在singleton bean实例化时只会创建一次。

@Service
public class TaskService {
    @Autowired
    Task task;

    public void startTask(){
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
        scheduledThreadPoolExecutor.scheduleAtFixedRate(task,1000,2000, TimeUnit.MILLISECONDS);
        scheduledThreadPoolExecutor.scheduleAtFixedRate(task,1000,2000, TimeUnit.MILLISECONDS);
    }
}

调度两个线程,实际上只初始化了一个Task实例,这样线程就不安全了。

如果singleton bean想每次都创建一个新的prototype bean的实例,一种方式是方法注入,可以通过实现ApplicationContextAware接口来获取ApplicationContext实例,通过getBean方法来获取到protrotype bean的实例。

@Service
public class TaskService implements ApplicationContextAware {
    @Autowired
    Task task;

    private ApplicationContext applicationContext;

    public void startTask(){
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
        task = applicationContext.getBean("task",Task.class);
        scheduledThreadPoolExecutor.scheduleAtFixedRate(task,1000,2000, TimeUnit.MILLISECONDS);
        task = applicationContext.getBean("task",Task.class);
        scheduledThreadPoolExecutor.scheduleAtFixedRate(task,1000,2000, TimeUnit.MILLISECONDS);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

另一种方式是代理模式,设置@Scope注解的一个代理字段proxyMode,默认是不使用,这里改为使用代理即可。

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Task implements Runnable {
    @Override
    public void run() {
    }
}

 

以上是关于Singleton与Prototype的主要内容,如果未能解决你的问题,请参考以下文章

singleton和prototype的区别

csharp C#代码片段 - 使类成为Singleton模式。 (C#4.0+)https://heiswayi.github.io/2016/simple-singleton-pattern-us

解决Spring中singleton的Bean依赖于prototype的Bean的问题

[Sprint] Bean Scope Singleton cs Prototype

[Spring Boot] Singleton and Prototype

Spring4-作用域singleton和prototype