我一直在研究 spring 和 spring mvc 框架,我很好奇 spring 容器如何为我们提供对我们作为参数传递给方法的任何接口或类类型的引用。
例如,当我们在 Web 应用程序中创建 Servlet 时,它会扩展 HttpServlet,因此当我们重写 doGet 或 doPost 方法时,Web 容器会实例化 Servlet 并将对 HttpServletRequest 和 HttpServletResponse 对象的引用传递给 doGet 或 doPost 方法,如下所示:
public class DemoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//container gives reference to request and response object
}
}
我想到的问题是 spring 容器如何知道它需要实例化什么对象引用,即它如何扫描方法,因为我们的类不会覆盖任何类或接口方法,以便它知道它需要提供对该对象的引用。由于这些类或接口类型未在应用程序上下文文件中声明为 beans。例如:
@Controller
@RequestMapping("/")
public class ContactController {
@RequestMapping(value="savecontact", method=RequestMethod.POST)
public String saveContact(@ModelAttribute("contact") Contact contact, BindingResult errors, HttpServletRequest request, HttpServletResponse response) {
...
}
}
Spring 如何提供对 BindingResult、HttpServletRequest、HttpServletResponse 对象以及我们作为参数传递给方法的任何其他 Spring 或 Servlet 类或接口类型的引用?它是否具有在应用程序启动时实例化的默认对象列表,或者是否扫描方法?
当您使用
@RequestMapping
注释控制器方法时,该方法的参数将成为参数解析过程的主题。接口 HandlerMethodArgumentResolver
及其实现是该机制的核心。该接口包含两个方法 supports
和 resolveArguments
RequestMappingHandlerAdapter
注册的默认解析器列表传递(检查 getDefaultArgumentResolvers
方法),如果解析器支持该类型,则调用 resolveArgument
方法并创建一个实例作为参数注入。
对于您声明的四种类型,各自的解析器是
ServletModelAttributeMethodProcessor
ErrorsMethodArgumentResolver
ServletRequestMethodArgumentResolver
ServletResponseMethodArgumentResolver
默认全部注册
基于参数解析机制,添加一个自定义解析器也很容易,它将实例化并注入任何自定义类型
作为主从答案的后续...关于@ModelAttribute参数
方法参数上的 @ModelAttribute 指示应从模型中检索参数。如果模型中不存在, 应首先实例化参数,然后将其添加到模型中。 一旦出现在模型中,参数的字段应该是 由具有匹配名称的所有请求参数填充。这个
在 Spring MVC 中称为数据绑定spring在“哪里”找到@ModelAttribute方法arg:
- 它可能已经在模型中
- 由于使用@SessionAttributes
- 由于同一控制器中的 @ModelAttribute 方法
- 可以根据 URI 模板变量和类型转换器来检索它(下面将更详细地解释)。
- 它可以使用其默认构造函数进行实例化。