将对象的新实例注入每个请求处理程序

Inject a new instance of an object into each request handler

我有很多 Spring 个 RestControllers,其方法用 RequestMapping 注释。我现在想在这些 RequestMapping 方法中注入一个自定义对象,并为每个请求创建一个自定义实例。

我想写这样的东西:

@RequestMapping("/search")
public SomeReturnObject foobar(@RequestParam("query") String query, MyRequestFoo foo) {
   // ...
}

现在我想创建一种机制,每次调用该方法(即每个请求)都会创建一个 MyRequestFoo 的新实例并将其注入到该方法中。如果使用参数注释而不是按类型注入会更好,那也可以(例如 @MyRequestInject MyRequestFoo foo)。

我需要知道我现在是否可以创建一个方法来创建 MyRequestFoo 的新实例,特别是针对该请求,如下所示:

public MyRequestFoo createRequestInstanceSomehow(HttpServletRequest request) {
   // extract some values from the HttpServletRequest and create a
   // new MyRequestFoo instance from that and return it
}

是否可以通过任何方式创建这样一种机制,以便我可以将自定义的每个请求对象注入到我的请求处理方法中?

如何将 MyRequestFoo 类型的实例变量放在控制器 class 上并自动装配它,将 Bean 定义的默认范围从 "Singleton" 更改为 "Request"?

查看 this link 或 Spring 参考资料 sheet!

我找到了一个解决方案,可以满足我的要求。

只需将 MyRequestFoo 创建为范围为 "request" 的 bean,您就可以通过 RequestContextHolder:

访问当前请求
@Component
@Scope("request")
public class MyRequestFoo {
   private final HttpServletRequest request;

   public MyRequestFoo() {
      request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
   }

   // do whatever you want with the request

}

现在我可以将其类型的新实例注入到任何请求处理程序方法中:

@RequestMapping("/search")
public SomeReturnObject search(MyRequestFoo foo) {
   // ...
}

并且 Spring 将自动负责实例化新实例。

无法将 MyRequestFoo 自动装配为实例变量,因为您无法将请求范围的 bean 自动装配到非请求范围的 bean 中。

Spring MVC 有一个直接支持您的请求的参数解析器构造。每个用 @RequestMapping 注释的处理程序方法都将进行参数解析,其中框架扫描处理程序参数,检查类型并实例化适当的对象。这就是注入请求、模型和许多其他类型背后的机制,只需在处理程序的方法签名中声明对象即可。

您可以编写自定义参数解析器来解析自定义类型并在方法中使用。程序简单三步流程

  1. 创建一个 POJO class,在你的情况下 MyRequestFoo

  2. 制作解析器,例如

      public class MyRequestFooResolver implements HandlerMethodArgumentResolver {
    
            @Override
            public boolean supportsParameter(MethodParameter parameter) {
    
                return parameter.getParameterType().equals(MyRequestFoo.class);
            }
    
            @Override
            public Object resolveArgument(MethodParameter parameter, 
                                          ModelAndViewContainer mavContainer,
                                          NativeWebRequest webRequest, 
                                          WebDataBinderFactory binderFactory)
            throws Exception {
    
                return new MyRequestFoo();
            }
        }
    

3.Register 解析器

 <mvc:annotation-driven>
     <mvc:argument-resolvers>
         <bean class="your.package.MyRequestFooResolver "></bean>  
     </mvc:argument-resolvers>
 </mvc:annotation-driven>

或在java配置中

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

  @Override
  public void addArgumentResolvers(List< Handlermethodargumentresolver > argumentResolvers) {
        MyRequestFooResolver myRequestFooResolver = new MyRequestFooResolver ();
        argumentResolvers.add(myRequestFooResolver );
  }
}

比你只通过添加类型作为处理程序方法参数来使用它

@RequestMapping("/search")
public SomeReturnObject search(MyRequestFoo foo) {
   // ...
}

由于您需要将特定于请求的信息传递给您的 bean,我建议改为将构建器 bean 注入您的控制器并从您的方法中调用 builder.build(request) 以创建新的每个请求实例。