SpringMVC @Scope会话不创建线程

时间:2013-05-12 19:01:37

标签: java spring

说我有以下课程......

@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);
    }

如果我最初启动我的应用程序,玩家是正确的,那么当我在同一个会话中,我再次使用新值调用此方法时,玩家不再像您期望的那样为空。但是,似乎没有创建新线程,如果我打开一个新的浏览器窗口(因此创建一个新会话)并调用此方法,它仍然具有上一个会话的值。

为什么@Scope(“session”)没有在线程池中创建新线程?

我已按预期在servlet上下文中指定了<context:component-scan base-package="com." />,除了服务方法之外,一切正常都可以作为单例,而不是像每个会话创建一个新的线程,比如说Java EE容器。

如果玩家被标记为静态,我会理解。

我还尝试将控制器标记为@Scope("session")(如下所示),但这似乎也没有任何影响。使我的Spring应用程序为新会话创建新线程的最佳方法是什么?

@Controller
@Scope("session")
public class PlayerController {

2 个答案:

答案 0 :(得分:3)

您正在以错误的方式使用@Scope注释。

引用docs

  

当与Component注释一起用作类型级注释时,指示用于注释类型实例的范围的名称。

     

当与Bean注释一起用作方法级注释时,指示用于从方法返回的实例的范围的名称。

因此,如果您使用的是java配置,则可以注释spring组件bean或创建bean的方法。 Java配置是它甚至编译的唯一原因(它不会在3.0之前的春天)

在你的情况下,注释是在普通的bean方法上,它没有任何意义。

解决正确的问题

看起来您正试图通过将查询结果存储在List<Player> players来实现数据库缓存。

不要那样做。使用其中一个预先构建的缓存抽象(spring有一个很好的缓存抽象)。

那么@Scope应该去哪里?

使用@Controller注释@Scope("session")无济于事,因为它会创建会话作用域控制器,但它们注入的服务仍然是单例。

仅注释Service bean也不起作用,因为@Controller是单例,并且它的依赖项在应用程序启动时自动装配。

注释@Service@Controller可能会有效,但看起来有点沉重。

最好避免状态。

答案 1 :(得分:1)

为每个请求创建新线程。

您的服务有一个不是线程安全的实例变量(播放器) - 它由所有线程共享。任何spring bean - 包括控制器和服务默认都是单例,你需要在服务注释上指定它的范围。

@Service("playerService")
@Scope("session")
public class PlayerServiceImpl 

但它最好(更简单,更容易扩展)来保持bean单例而不依赖于实例变量(除非它们也由spring / threadsafe / singletons管理)。