假设我有下面的类。
@Controller
public class WebController {
@Autowired PersonService personService;
@RequestMapping(value = "/get", method = RequestMethod.GET)
@ResponseBody
@Scope("session")
public List<Player> getPerson(String personName) {
return playerService.getByName(personName);
}
}
现在,这将调用以下服务...
@Service("playerService")
public class PlayerServiceImpl implements PlayerService {
private List<Player> players;
@Override
@Transactional
public List<Player> getByName(final String name) {
if (players == null) {
players = getAll();
}
return getValidPlayers(name);
}
如果我最初启动我的应用程序,players是空的,正确的,然后在同一会话中,我用一个新的值再次调用这个方法,players不再是空的,正如你所期望的。但是,似乎没有创建新的线程,如果我打开一个新的浏览器窗口(因此创建了一个新的会话)并调用此方法,它仍然具有前一个会话中的值。
为什么@Scope("session")不在线程池中创建一个新线程?
不出所料,我已经在servlet上下文中指定了<context:component-scan base-package="com." />
,除了服务方法都作为单例运行,而不是像Java容器那样为每个会话创建一个新线程外,其他一切都运行得很好。
如果播放器被标记为静态,我可以理解。
我还尝试将我的控制器标记为@Scope("session")
(如下所示),但这似乎也没有任何影响。让我的Spring应用程序为新会话创建新线程的最好方法是什么?
@Controller
@Scope("session")
public class PlayerController {
发布于 2013-05-12 19:14:07
您正在以错误的方式使用@Scope
注释。
引用docs
当与组件批注一起用作类型级批注时,
指示用于带批注的类型的实例的作用域的名称。
当与Bean注释一起用作方法级注释时,表示用于从方法返回的实例的作用域的名称。
因此,如果您使用的是java config,则可以注释spring组件bean或创建bean的方法。Java配置是它编译的唯一原因(在3.0版本之前的spring中不会)
在您的例子中,注释位于普通的bean方法上,它没有任何意义。
解决正确的问题
看起来您正试图通过将查询结果存储在List<Player> players
中来实现db缓存。
别干那事。取而代之的是使用一个预先构建的缓存抽象(spring有一个非常好的)。
因此, @Scope
应该去哪里?
用@Scope("session")
注释@Controller
不会有什么帮助,因为它将创建会话作用域控制器,但它们注入的服务仍然是单例的。
只注释Service bean也不起作用,因为@Controller
是一个单例,它的依赖关系在应用程序启动时自动连接。
同时注释@Service
和@Controller
可能会起作用,但看起来有点笨拙。
最好是完全避免使用state。
发布于 2013-05-12 19:43:12
为每个请求创建新的线程。
您的服务有一个实例变量(播放器),它不是threadsafe -它由所有线程共享。默认情况下,任何spring bean -包括控制器和服务都是单例的,您需要在服务注释中指定其作用域。
@Service("playerService")
@Scope("session")
public class PlayerServiceImpl
但最好(更简单,更容易扩展)让bean保持单例,而不依赖于实例变量(除非它们也是由spring/threadsafe/ singletons管理的)。
https://stackoverflow.com/questions/16510976
复制相似问题