据我所知,默认情况下 Spring bean 是单例的。
我想要的是考虑实例属性使 bean 线程安全。
我将尝试用一个简单的示例向您展示。
考虑以下代码:
@Controller
public class MyServlet {
@Autowired
private HelloService service;
@RequestMapping(value="/hello", method = RequestMethod.GET)
public void sayHello(HttpServletRequest req, HttpServletResponse res) throws IOException {
service.doStuff();
}
}
public class HelloService {
private int i = 1;
public void doStuff() {
System.out.println("Started " + i);
i++;
System.out.println(Thread.currentThread().getName() + " Done " + i);
}
}
输出将是这样的:
32911580@qtp-28064776-0 - Started 1
7802158@qtp-28064776-2 - Started 2
32911580@qtp-28064776-0 - Done 3
7802158@qtp-28064776-2 - Done 3
这证明“i”变量在多个线程之间共享。
我还尝试将 HelloService bean 定义为原型(prototype),如下所示
<bean id="helloService" class="my.package.HelloService" scope="prototype" />
但结果是一样的。
我发现解决这个问题的唯一方法是: - 将声明移到 doStuff() 方法中,但这不是我想要的 - 创建 doStuff() 方法,但这意味着有锁
我想要的是在每次调用时都有一个新的 HelloService 实例。
谁能帮帮我? 提前致谢。
更新
我找到了使用查找方法注入(inject)方法的解决方案。 http://static.springsource.org/spring/docs/3.1.1.RELEASE/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection
最佳答案
由于您只有一个 MyServlet 实例,因此您也只有一个 HelloService 实例。
以下 spring 作用域之一有帮助: request 每个 HTTP 请求的新实例。 session 在 servlet 容器中创建的每个新 HttpSession 的类的新实例。
这将改变代码的语义。如果您在范围请求中声明 bean,您的计数器将始终为 1。
要拥有一个唯一的无锁计数器,您可以使用 java.util.concurrent.atomic.AtomicInteger。
另一方面,锁也没有什么不好的。除极端情况外,大多数情况下性能影响可以忽略不计。
构建应用程序后,使用 http://vmlens.com 检查它对于竞争条件。
关于spring - 如何使 Spring bean 线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15002226/