首页 > 解决方案 > Spring RequestScope bean 未按预期工作

问题描述

我正在尝试了解有关在项目中使用的 Spring bean 范围的更多信息。我创建了一些测试类,但没有得到我期望的行为。

我创建了以下组件,并且我希望这个 bean 仅在 HTTP 请求期间持续存在。

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserDataContainer {
    
    public int requestCount = 0;

}

以下控制器使用该组件。

@Controller
@RequestMapping("/hello")
public class HelloController {
    
    @Autowired
    private UserDataContainer userData;

    @GetMapping
    public String get(Model model) {
        model.addAttribute("prev", userData.requestCount);
        
        userData.requestCount++;
        
        model.addAttribute("curr", userData.requestCount);
        
        return "test";
    }

}

我的麻烦是,似乎没有为每个请求创建一个新的 UserDataContainer 实例。每当我加载此页面时,我都会看到“prev”和“curr”的值不断增加,而不是在每个请求开始时重置为 0。我是否误解了这应该如何工作,或者没有正确实施。

标签: javaspringspring-boot

解决方案


这里的问题是请求范围的 bean 不是由您的控制器直接调用的。

相反,控制器使用代理来调用请求范围的 bean(在这种情况下,代理是基于您的代理模式注释的 cglib 代理,即:ScopedProxyMode.TARGET_CLASS

代理只包装请求范围 bean 的方法,而不是它的变量。

所以简而言之,将请求范围 bean 的实例变量封装到一个方法中,然后从 Controller 调用该方法。

像这样的东西:

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserDataContainer {

   private int requestCount = 0;
   public int incrementRequestCount(){
        requestCount++;
        return requestCount;
   }

   public int getRequestCount(){
         return requestCount;
   }
} 

然后在您的控制器中,只需调用公共方法

@GetMapping
public String get(Model model) {
    model.addAttribute("prev", userData.getRequestCount());

    model.addAttribute("curr", userData.incrementRequestCount());
    
    return "test";
}

推荐阅读