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的主要内容,如果未能解决你的问题,请参考以下文章
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