1

假设我有以下课程......

@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") 不在线程池中创建新线程?

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

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

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

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

2 回答 2

3

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

引用文档

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

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

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

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

解决正确的问题

看起来您正在尝试通过将查询结果存储在List<Player> players.

不要那样做。改用其中一种预构建的缓存抽象(spring 有一个非常好的)。

那么应该@Scope去哪里呢?

注释不会@Controller有帮助,因为它会创建会话范围的控制器,但他们注入的服务仍然是单例。@Scope("session")

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

注释两者@Service并且@Controller可能会起作用,但似乎有点笨拙。

最好完全避免状态。

于 2013-05-12T19:14:07.473 回答
1

为每个请求创建新线程。

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

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

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

于 2013-05-12T19:43:11.723 回答