Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在春季,prototype和singleton之间是否存在性能差异?_Java_Spring - Fatal编程技术网

Java 在春季,prototype和singleton之间是否存在性能差异?

Java 在春季,prototype和singleton之间是否存在性能差异?,java,spring,Java,Spring,当我使用spring框架编写业务代码时,我总是使用singleton范围,而避免使用prototype范围。我认为prototype和singleton之间存在性能差异。由于prototype的作用域,spring在每次调用时都会创建一个新实例。我认为它比使用单例作用域慢。我说得对吗?我对性能考虑得太多了吗?是的,您是对的,原型范围的bean会消耗更多的资源。根据报告: bean部署的非单例原型范围导致每次对特定bean发出请求时都创建一个新的bean实例 构造函数在每次请求时被调用,而不是在单

当我使用spring框架编写业务代码时,我总是使用singleton范围,而避免使用prototype范围。我认为prototype和singleton之间存在性能差异。由于prototype的作用域,spring在每次调用时都会创建一个新实例。我认为它比使用单例作用域慢。我说得对吗?我对性能考虑得太多了吗?

是的,您是对的,原型范围的bean会消耗更多的资源。根据报告:

bean部署的非单例原型范围导致每次对特定bean发出请求时都创建一个新的bean实例

构造函数在每次请求时被调用,而不是在单例作用域bean中只调用一次。但还有另一个方面需要考虑。报告说:

因此,尽管对所有对象调用初始化生命周期回调方法,而不考虑范围,但对于原型,不会调用配置的销毁生命周期回调。客户机代码必须清理原型范围的对象,并释放原型bean所持有的昂贵资源。要让Spring容器释放原型范围的bean所持有的资源,请尝试使用定制的bean后处理器,该后处理器持有对需要清理的bean的引用

如果您想避免内存不足异常,您必须小心bean的破坏


除非真的需要,否则最好使用单例范围的bean。

我认为在最基本的意义上,您不会看到原型和单例之间有任何明显的性能差异

的确,在应用程序上下文中只有一个单例bean实例,使用“prototype”范围定义的bean实例是为每个对该bean的请求创建的,然而,我们谈论的是新对象创建的性能,它现在非常便宜,并且针对非昂贵的对象进行了优化

然而,这里有一些警告:

如果bean的构造函数调用了一些非常昂贵的代码,那当然不是spring的错,因为程序员是这样编写代码的,但实际上,每次创建bean时,都会调用一些非常昂贵的代码,这样会消耗性能

更有趣的是:我们通常不会在constructor中放置这样的代码,而是使用“生命周期”方法,如
@PostConstruct
/
@PreDestroy

对于单例,spring将在创建单例时调用post-construct方法一次,然后将bean放到应用程序上下文中。 当应用程序上下文关闭时(通常在应用程序关闭时),调用pre-destroy方法释放资源,等等

但是,对于原型范围的bean,情况并非如此: Spring根据对bean的每个请求创建它们,然后调用post-construct方法,再次为它创建的bean的每个实例调用,然后不将实例存储在应用程序上下文中。这意味着spring根本不调用预销毁方法(因为它不知道这些对象是谁,在它们被创建之后,它不会真正管理它们)。 因此,这可能(同样不是spring的故障)导致两者之间的严重性能差异


如果我们更进一步,有时spring必须将对象包装到某种代理中。对于接口,这些代理通常使用
java.lang.Proxy
完成,或者使用基于继承的
Cglib
完成。现在,当我们谈论将原型范围的bean包装到代理中时,这一事实本身就可能成为性能上严重差异的根源,因为代理是在运行时生成的,而使用代理(尤其是使用CGlib)包装对象非常昂贵。

我可以理解这个问题,我最近一直在研究它。对象的构造非常便宜,除非它们实际上在构造函数中执行一些繁重的工作。在一个语句中构建一组lambda时,您从来不会三思而后行。这不是问题所在

问题在于Spring的低效率,它的架构设计不正确。我最近对Spring和Guice进行了基准测试。使用Spring时,单例的速度稍快一些,但原型的速度要慢20倍

从代码健全性的角度来看,您应该始终更喜欢原型。Guice默认为原型
javax.inject.inject
文档默认为原型。Spring列出了一些模糊的历史原因,并没有提到单身人士

原型更安全,因为它们不会意外地存储状态并在错误的上下文中使用。他们不能存储一个请求中的“userId”并在另一个请求中使用,因为对于原型,每次都会创建一个全新的干净状态实例。这就是我学习这种模式的原因:在使用单例和RequestScope提供程序时,我们意外地缓存了错误的用户上下文。哎哟避免这个错误很重要。获得CPU是一个小得多的问题


总而言之:使用原型获得更好的代码,如果性能非常重要,不要使用Spring。

如果您担心对象实例化本身:那么是的,您考虑得太多了。唯一真正不同的是,如果原型中有一些繁重的逻辑(一遍又一遍地重复是多余的)。例如,如果每次都创建一个新的数据库连接。在适当的情况下使用Singleton(即在整个应用程序生命周期中可重用),在适当的情况下使用Prototype(即包含特定于每个调用/请求/使用的内容)。即使在Prototype作用域中,也可能只创建和使用一个bean,具体取决于应用程序的连接方式。所以你的问题不够详细。@Ortamola“你必须照顾好自己。”