必须Spring MVC类是线程安全的
如果使用Spring MVC,那么组件类( @Controller
@Service
, @Repository
@Controller
, @Service
@Repository
)必须是线程安全的吗?
也就是说,如果我的@Controller
有一个@RequestMapping
方法,是否可以通过多个线程同时为同一个控制器对象调用该方法?
( 之前已经提到了这种情况,但没有得到回答)。
特定
@Controller public class MyController { @RequestMapping(value = "/index") public String respond() { return "index"; } }
Spring将创建一个MyController
实例。 这是因为Spring解析了你的配置,
,看到了@Controller
(就像@Component
)并实例化了带注释的类。 因为它也看到@RequestMapping
,它会为它生成一个HandlerMapping
,请参阅此处的文档 。
DispatcherServlet
接收的任何HTTP请求都将通过之前注册的HandlerMapping
调度到此控制器实例,通过该实例上的javareflection调用respond()
。
如果你有像实例字段
@Controller public class MyController { private int count = 0; @RequestMapping(value = "/index") public String respond() { count++; return "index"; } }
count
将是一个危险,因为它可能被许multithreading修改,并且它的更改可能会丢失。
您需要了解Servlet容器的工作原理。 容器实例化Spring MVC DispatcherServlet
一个实例。 容器还管理一个用于响应连接的线程池,即。 HTTP请求。 当这样的请求到达时,容器从池中选择一个Thread,并在该Thread内执行DispatcherServlet
上的service()
方法,该方法将DispatcherServlet
到Spring为您注册的正确的@Controller
实例(来自您的配置)。
所以,是的,Spring MVC类必须是线程安全的。 您可以通过为类实例字段使用不同的范围或仅使用局部变量来执行此操作。 如果做不到这一点,您需要在代码中的关键部分周围添加适当的同步。
默认情况下,控制器是单例,因此必须是线程安全的。 但是,您可以将控制器配置为请求或会话作用域,即:
@Controller @Scope("session") public class MyController { ... }
具有会话范围的控制器可以帮助管理会话状态。 可以在Spring-MVC中使用会话(包括“作用域代理”)和如何在Spring MVC中获取会话对象中找到对不同模式的良好描述。 一些呈现的模式需要请求范围 。
如果您有数据无法为每个请求计算多个数据,那么请求范围也很有用。
当然是。
最好是那些是无状态的,这使得它们默认是线程安全的。 如果没有共享的,可变的状态则没有问题。
基本上答案应该是肯定而不是。 除了非常严重的原因。 不是因为Spring同步为你工作 – 它没有这样做(默认情况下,Controller是一个Singleton bean)。 粗略的线程安全必须保持在方法调用中,但通常Servlet的机制消除了同步某事的必要性,因为在线程内执行的请求。 因此,在调用任何@RequestMapping带注释的方法期间,整个调用堆栈在一个线程中执行。 在根中,它是从Servlet的service-do(Get,Post ..)方法传出,然后是Spring构建的处理程序映射(参见http://www.studytrails.com/frameworks/spring/spring-mvc -handler-mappings / http://technicalstack.com/dispatcher-servlethandlermapping-controller/例如)。 在URL解析后,Spring从处理程序的映射调用处理方法。 没有其他技巧。 所以想想,你在doPost(…)中使用DispatchServlet的方法。 Servlet线程安全吗? 没有粗糙。 你可以做到线程安全 – 是的,使用锁,同步,还有什么,让你的Servlet成为瓶颈! 关于控制器完全相同。 一个doGet / Post / Servlet的其他方法基本上都是一个function模型,所有数据都在HttpServletRequest对象中。 应该在Controller对象使用的数据类中使用相同的方式,而使用堆栈而不是字段。 您可以通过支付瓶颈价格来同步对它们的访问权限。 粗糙你可以使用primefaces,是否需要? 如果你需要在会话期间保持任何状态,你可以在@Controller之后使用@Scope(“session”)或者(对于单身控制器)使用带签名(…,HttpSession)的处理程序方法,它们都有利弊。 但请注意,您创建了额外的CPU和GC费用。 无论如何,当您想要使用字段并退出无状态概念时,您负责控制器线程安全。 通常,缓存(例如redis)对于客户端状态保持是优选的。 至少可以在发生故障时恢复状态。 超出会话范围的有状态控制器基本上没有理由。