提问人:Raedwald 提问时间:5/28/2013 最后编辑:Raedwald 更新时间:4/29/2023 访问量:32981
Spring 组件类必须是线程安全的
Must Spring component classes be thread-safe
问:
如果你使用 Spring,你的组件类 (, , ) 必须是线程安全的吗?或者 Spring 是否以线程安全的方式使用它们,这样您就不必担心线程安全?@Controller
@Service
@Repository
也就是说,如果我的 中有一个方法,是否可以由多个线程同时为同一个控制器对象调用该方法?@RequestMapping
@Controller
(这之前有人问过,但没有这样回答)。
答:
是的,当然。
最好是它们是无状态的,这样默认情况下它们线程是安全的。如果没有共享的可变状态,则没有问题。
评论
@Component
鉴于
@Controller
public class MyController {
@RequestMapping(value = "/index")
public String respond() {
return "index";
}
}
Spring 将创建一个 的实例。这是因为 Spring 解析了您的配置,看到(类似于)并实例化带注释的类。因为它也看到,所以它为它生成一个,请参阅此处的文档。MyController
<mvc:annotation-driven>
@Controller
@Component
@RequestMapping
HandlerMapping
接收到的任何 HTTP 请求都将通过之前注册的 Send 到此控制器实例,通过该实例上的 java 反射调用。DispatcherServlet
HandlerMapping
respond()
如果您有类似
@Controller
public class MyController {
private int count = 0;
@RequestMapping(value = "/index")
public String respond() {
count++;
return "index";
}
}
count
将是一种危险,因为它可能会被许多线程修改并且对它的更改可能会丢失。
您需要了解 Servlet 容器的工作原理。容器实例化 Spring MVC 的一个实例。该容器还管理一个线程池,它使用它来响应连接,即。HTTP 请求。当这样的请求到达时,容器从池中选取一个线程,并在该线程中执行该方法,该方法调度到 Spring 为您注册的正确实例(从您的配置中)。DispatcherServlet
service()
DispatcherServlet
@Controller
所以是的,Spring MVC 类必须是线程安全的。为此,您可以为类实例字段使用不同的作用域,或者只使用局部变量。如果做不到这一点,则需要在代码中的关键部分周围添加适当的同步。
默认情况下,控制器是单例的,因此必须是线程安全的。但是,您可以将控制器配置为请求或会话范围,即:
@Controller
@Scope("session")
public class MyController {
...
}
具有会话范围的控制器有助于管理会话状态。可以在 Spring-MVC 中使用会话(包括“作用域代理”)和如何在 Spring MVC 中获取会话对象中找到对不同模式的良好描述。介绍的一些模式需要请求范围。
如果您的数据无法承受每个请求计算多个数据,则请求范围也很有用。
评论
如果一个 Spring 组件以及另一个类可以由多个线程同时使用,则它必须是线程安全的。默认情况下,Spring 组件是单例,可以从不同的线程调用。从这个角度来看,它的 STATE 应该是线程安全的。 另一方面,单例 Spring Bean 通常在线程池的线程调用堆栈中提供请求。通常,Spring 组件具有字段,这些值是注入的接口或属性。唯一需要注意安全的是当状态对象保存在 Bean 中时。通常,由于服务器已进行负载平衡,并且状态保存在缓存或数据库中,因此不会使用它。 因此,单例 Bean 应该用作一组函数,它将数据作为相关方法的参数进行传输,并且其字段不应保留业务数据,而应仅保留用于调用进度的注入 Bean。 Spring 的控制器就是一个例子。它的方法由Tomcat的线程调用,控制器方法映射的方式,所有的调用堆栈都在一个线程中完成。控制器的方法调用 DAO 方法并在同一线程中返回结果。 会话通常从一个会话持久化到另一个会话,这由 Spring 处理。 因此,除了极少数情况外,没有必要注意螺纹安全。
评论
@Controller
@RequestMapping