问题分析
我们先来看下面的代码,判断一下两个接口请求的值分别多少。
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返回结果为:
通过上述两种对比的结果我们可以发现,单例是不安全的,会导致属性重复使用。
解决方案
- 尽量避免在controller中定义成员变量。
- 如果必须定义成员变量时候,需要通过注解@Scope(“prototype”),将其设置为多例模式。
- 在Controller中使用ThreadLocal变量