简体   繁体   English

Spring bean的Singleton实现

[英]Singleton implementation of a Spring bean

We have a Spring bean implemented as a singleton (default). 我们有一个实现为单例的Spring bean(默认)。 This bean is used as part of an web-service, and at times when multiple simultaneous requests are triggered, the responseholder (singleton bean) throws a NullPointerException when trying to retrieve. 该bean用作Web服务的一部分,并且有时触发多个同时请求时,响应持有者(单个bean)在尝试检索时会引发NullPointerException。 This usually happens when the response is build, and then a new request is triggered before sending the original response back. 这通常在生成响应时发生,然后在发送回原始响应之前触发新请求。

Can this be due to the Singletion implementation of the bean? 这可能是由于bean的Singletion实现引起的吗? If yes, is there wouldn't changing to prototype solve my problem. 如果是的话,是否会改变原型以解决我的问题。 What about initiating it with the new operator always? 总是与新操作员一起启动该怎么办? Will there be any performance impacts on doing so? 这样做会对性能产生影响吗? Or is there a better way. 或者,还有更好的方法。

Any help would be greatly appreciated. 任何帮助将不胜感激。

Edit : 编辑

Code details 代码详细信息

public class BuildToolRequestProcessor {

private BuildToolResponse buildToolResponse;
.....


//And it has been referenced in the code in different methods, setting the response details..

public String process(BuildToolRequestXml buildToolRequestXml) throws Exception {

buildToolResponse.setLocation(location);
...


public String handleDetails(BuildToolRequestXml buildToolRequestXml) throws Exception {


buildToolResponse.setSchedule(schedule);
...

// And in another method, when I try to retrieve the Location, it throws a Null Pointer Exception..

buildToolResponse.getLocation().getPinCode()


//Bean configuration

<bean id="buildToolResponse"
      class="com.raj.buildTool.processor.BuildToolResponse"/>

Additional Notes : I tried introducing a delay before bulding the response of the first request, shooting another request. 附加说明 :我尝试引入延迟,然后才扩展第一个请求的响应,拍摄另一个请求。 The second request resets the Location to NULL, and hence NPE is thrown while trying to retrieve the Location. 第二个请求将位置重置为NULL,因此在尝试检索位置时会抛出NPE。 Could this be because of the singleton? 可能是因为单身吗? Also I haven't used initialized the buildToolResponse again with the new operator, but the class BuildToolResponse extends from BuildToolResponseBuilder, which I am initializing using 'new' to build the response. 另外,我还没有使用new运算符再次初始化buildToolResponse,但是BuildToolResponse类是从BuildToolResponseBuilder扩展而来的,我正在使用“ new”进行初始化以构建响应。

Can this be due to the Singletion implementation of the bean? 这可能是由于bean的Singletion实现引起的吗? If yes, is there wouldn't changing to prototype solve my problem. 如果是的话,是否会改变原型以解决我的问题。

If you have a singleton bean, make sure that this bean does not maintain any state. 如果您有一个singleton bean,请确保该bean 保持任何状态。 This means, it should not have any field that is reinitialized based on some methods, except for the injection of another beans or resources that is done by Spring. 这意味着,它不应具有基于某些方法重新初始化的任何字段,除非由Spring注入另一个bean或资源。 This may cause concurrency issues, specially when the bean is used in several threads (in this case, to attend multiple requests done to your web service). 这可能会导致并发问题,尤其是在多个线程中使用Bean时(在这种情况下,是为了处理对Web服务执行的多个请求)。

This is an example of a bad design for a Spring bean that will be used on multiple threads: 这是一个将在多个线程上使用的Spring bean设计不良的示例:

@Component
public class SingletonByDefaultBean {
    private StringBuilder responseBuilder;

    @Autowired
    private FooService fooService;

    public String methodUsedInSeveralThreads() {
        //here you will have a concurrency issue
        responseBuilder = new StringBuilder();
        //write contents into the response
        //...
        //return the response
        return responseBuilder.toString();
    }
}

To solve this, you have two approaches: 要解决此问题,您有两种方法:

  1. Remove any state of the bean and move the attributes into method local variables: 删除Bean的任何状态,并将属性移到方法局部变量中:

     @Component public class SingletonByDefaultBean { //private StringBuilder responseBuilder; @Autowired private FooService fooService; public String methodUsedInSeveralThreads() { StringBuilder responseBuilder = new StringBuilder(); //write contents into the response //... //return the response return responseBuilder.toString(); } } 
  2. Change the scope of the bean to prototype 将bean的范围更改为原型

     @Component @Scope("prototype") public class SingletonByDefaultBean { private StringBuilder responseBuilder; @Autowired private FooService fooService; public String methodUsedInSeveralThreads() { responseBuilder = new StringBuilder(); //write contents into the response //... //return the response return responseBuilder.toString(); } } 

What about initiating it with the new operator always? 总是与新操作员一起启动该怎么办?

Refer to this answer to know how you can create instances your classes manually and make them been managed by Spring. 请参阅此答案以了解如何手动创建类的实例并使它们由Spring管理。 It is not that easy and I would recommend using these approaches only if you really understand what you're doing. 并不是那么容易,并且只有在您真正了解自己在做什么的情况下,我才建议使用这些方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM