由于缺乏弹簧知识,我对范围bean依赖性有一些严重的怀疑。
我已经阅读了3.5.4.5作为依赖关系的Scoped bean的参考手册,并已成功实现了一个例子。
然而,在进一步发展之前,我想分享我的担忧。
让我分享一下我的用例和一些实现细节
对于每个用户请求,我想为每个用户创建一个城市。
@Configuration
public class CityFactory{
@Bean(name = {"currentCity" , "loggedInCity"})
@Scope(value = WebApplicationContext.SCOPE_REQUEST,proxyMode = ScopedProxyMode.TARGET_CLASS)
@Autowired
public CityBean getCityBean(HttpServletRequest request) {
return CityUtil.findCityWithHostName(request.getServerName());
}
对于每个请求,我想将此城市注入单一作用域控制器,该控制器是控制器的默认作用域。
@RequestMapping("/demo")
@Controller
public class DemoController {
@Autowired
CityBean city;
@RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
public ModelAndView helloWorld(@PathVariable("name") String name, Model model) {
Map<String, Object> myModel = new HashMap<String, Object>();
model.addAttribute("hello", name);
model.addAttribute("test", "test in " + city.getDomainName() + " !!! ");
return new ModelAndView("v3/test", "m", model);
}
}
我的问题:
1)有竞争条件吗?我担心上下文切换会在多请求环境中破坏我的应用程序。
2)我知道另一种解决方案,即每个请求创建一个控制器,但它比当前解决方案更容易出错。因为另一个开发人员可以忘记范围控制器来提出请求。
如何让控制器全局请求范围?只是因为不太好奇。
...谢谢
答案 0 :(得分:0)
没有竞争条件 - 每个请求都有自己的线程
但我认为有一种更简单的方法可以做你想做的事。您可以拥有CityBean
:
@Service
public class CityBean {
public String getDomainName(String serverName) {
// obtain the name based on the server name
}
}
在你的控制器中:
@Autowired CityBean bean
HttpServletRequest
作为参数传递给方法,然后调用cityBean.getDomainName(request.getServerName());
(如果你使用一些ORM,也许你会有一个City
实体,你可以获取和传递,只要小心懒惰的集合)
答案 1 :(得分:0)
这里没有竞争条件。
这是范围代理的重点 - 注入CityBean
的{{1}}实例是一个代理,它将其方法的调用委托给DemoController
的实际请求绑定实例,以便每个请求都使用自己的CityBean
。
我同意你不应该让控制器本身请求范围 - 这会让其他人感到困惑,因为它不是Spring MVC应用程序中的典型方法。
你也可以按照Bozho的方法建议并完全摆脱请求范围的bean,尽管这种方法有一个缺点,因为它要求你在控制器方法中添加额外的参数。