Spring的Controller怎样保证线程安全

问题分析

我们先来看下面的代码,判断一下两个接口请求的值分别多少。

import com.sun.proxy.model.system.OptResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author ybc
 * @date 2020/08/05 21:30
 */
@RestController
public class TestController {
    
    
    //定义测试成员变量
    private int num = 0;

    @RequestMapping(value = "/testOne",method = RequestMethod.GET)
    public OptResult<Integer> testOne() {
    
    
        return new OptResult<>(OptResult.OptStat.OK,++num);
    }

    @RequestMapping(value = "/testTwo",method = RequestMethod.GET)
    public OptResult<Integer> testTwo() {
    
    
        return new OptResult<>(OptResult.OptStat.OK,++num);
    }

}

如果这个Controller是线程安全的,两个接口请求的值应该是相同的。

问题验证

请求接口testOne返回结果为:
在这里插入图片描述
请求接口testTwo返回结果为:
在这里插入图片描述
两个接口返回的值是不同的,显然线程不安全。

下面我们来改造一下代码,让controller增加作用多例 @Scope(“prototype”),重新运行程序。

@RestController
@Scope("prototype")
public class TestController {
    
    
    //定义测试成员变量
    private int num = 0;

    @RequestMapping(value = "/testOne",method = RequestMethod.GET)
    public OptResult<Integer> testOne() {
    
    
        return new OptResult<>(OptResult.OptStat.OK,++num);
    }

    @RequestMapping(value = "/testTwo",method = RequestMethod.GET)
    public OptResult<Integer> testTwo() {
    
    
        return new OptResult<>(OptResult.OptStat.OK,++num);
    }

}

请求接口testOne返回结果为:
在这里插入图片描述
请求接口testTwo返回结果为:
在这里插入图片描述
通过上述两种对比的结果我们可以发现,单例是不安全的,会导致属性重复使用。

解决方案

  1. 尽量避免在controller中定义成员变量。
  2. 如果必须定义成员变量时候,需要通过注解@Scope(“prototype”),将其设置为多例模式。
  3. 在Controller中使用ThreadLocal变量

猜你喜欢

转载自blog.csdn.net/cyb_123/article/details/107826018