开发中遇到一个问题:有个小伙伴在controller中定义了一个私有的全局变量:id,想在请求add方法时给id赋值,然后在请求update方法时拿过来用。因为我们开发的是B/S的项目,他竟然做到了,这让我感到很惊讶。之前从没遇到过这种问题啊。这样明显不对啊。在高并发的时候,这个id可以被N个人修改,然后最后被修改的值又被N个人拿过来使用。明显会有问题。
所以后来我怀疑跟controller的生命周期有关,也许这个controller被sprint托管后,就一直存在。
具体的原理是什么?麻烦热心人解答下,谢谢。
代码如下:
@RestController
@RequestMapping("/test")
public class TestController {
private Long id;
@PostMapping("/update")
public ResponseModel update() {
System.out.println(this.id);
return null;
}
@GetMapping("/add")
public ResponseModel add(Long id) {
this.id = id;
System.out.println(this.id);
return null;
}
}
我没看过springboot的源码,不过我知道spring默认是单例的。
既然它们都是一个家族的,springboot是单例的也不是什么难以理解的事情。
既然是单例的,所有对这个Controller的请求最终都给到了同一个对象,而这个id就在这个对象里面,可以共享也就很正常了。
main()
{
var httpContext = httpListner.WaitForClientRequest();//先假设同步通信(两大层,一层是nginx、iis之类的http协议,为什么加个context呢,因为还有一层他把http 又处理request、response、 cookie、header、session......),异步一个道理
//这里怎么实现框架呢?
//很多controller对吧?那怎么映射到具体的controller并执行呢?我们能否通过 url 和 method 反射
var controllerXX = ???;
action(httpContext)
//这就是框架逻辑了,这下你可以把static 变量带进去看一下分析了。
以上就是整个通讯粗逻辑,这是处理一次的,加上while后就是一直运行的了,当然更高效一些改为异步。
}
那么上述问题又可能会有一些问题,比如有的服务器有空闲重启策略(因为coder代码可能差劲嘛),static是不是需要持久化,不然重启后变成了0。
跟spring工厂模式关系不大吧,这样写是有问题的,就算是controller一直存在,那也就相当于普通的类的static变量,并发的时候同时操作还是有问题的
没搞过Java,不知道你们用的什么框架,建议看看源码。感觉这样做不保险,也许是框架里有缓存机制,但是如果不清楚缓存机制的具体工作方式,万一被清除了就影响业务了,不建议这样做。
controller是一个bean也就是一个实例,你调用两个接口访问的都是同一个controller(实例), 成员变量id当然会随之改变
知道怎么回事了。这个跟.net core类似。每个bean都是有生命周期的,默认是单例模式。如果不想单例模式,可在bean上面添加注解@scope("request")就行了。