据我所知,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”var在多个线程之间共享。
我也尝试将HelloService bean定义为原型,就像这样
<bean id="helloService" class="my.package.HelloService" scope="prototype" />
但结果是一样的。
我发现解决这个问题的唯一方法是: - 将声明移到doStuff()方法中,但这不是我想要的 - 制作doStuff()方法,但这意味着有锁
我想要的是每次调用都有一个新的HelloService实例。
任何人都可以帮助我吗? 提前谢谢。
我使用lookup-method找到了方法注入的解决方案。 http://static.springsource.org/spring/docs/3.1.1.RELEASE/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection
答案 0 :(得分:2)
由于您只有一个MyServlet实例,因此您只有一个HelloService实例。
以下弹簧范围之一有助于: request 每个HTTP请求的新实例。 session 在servlet容器中创建的每个新HttpSession的类的新实例。
这将改变代码的语义。如果在范围请求中声明bean,则计数器将始终为1。
要拥有一个没有锁的唯一计数器,可以使用java.util.concurrent.atomic.AtomicInteger。
另一方面,锁没有什么不好。除极端情况外,大多数情况下性能影响都是可以忽略的。
构建完应用程序后,请使用http://vmlens.com检查竞争条件。
答案 1 :(得分:0)
添加到托马斯&#39;回答,对于服务bean,请求范围是有状态的最佳选择。线程安全组件,因为在该范围内通常只调用一个实例。
如果在特定应用程序范围内需要多个(有状态和线程安全)bean,那么原型范围将是最合适的选择。
答案 2 :(得分:0)
我也尝试将HelloService bean定义为原型,但结果是一样的。
你得到了相同的结果,因为你的MyServlet
是单身人士。因此,您只有一个MyServlet
实例,因此您只有一个HelloService
实例。如果您将MyServlet
作为原型bean ,那么每次都会获得新的实例