问题分析
我们先来看下面的代码,判断一下两个接口请求的值分别多少。
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变量
Spring线程安全与@Controller注解详解
本文探讨了在Spring框架中,@Controller注解下成员变量的线程安全问题,通过实例演示了单例模式下成员变量的共享导致的数据混乱,并提供了使用@Scope(“prototype”)和ThreadLocal变量的解决方案。
549

被折叠的 条评论
为什么被折叠?



