Search code examples
javaspringspring-mvcservletsdependency-injection

How does Spring container give reference to interface or class type we pass as method arguments?


I have been studying spring and spring mvc framework, and I am curious to know that how the spring container gives us the reference to whatever Interface or Class type we pass as an argument to our methods.

For instance, when we create a Servlet in a web application it extends HttpServlet so when we override the doGet or doPost method the web container instantiates the servlet and pass a reference to HttpServletRequest and HttpServletResponse objects to doGet or doPost methods as:

public class DemoServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //container gives reference to request and response object
    }
}

The question that comes to my mind is how the spring container knows what object reference it need to instantiate i.e how does it scans the methods as our class does not override any Class or Interface method so that it can know that it needs to provide the reference to that object. As these class or interface types are not declared as beans in application context file. For instance:

 @Controller
 @RequestMapping("/")
 public class ContactController {

 @RequestMapping(value="savecontact", method=RequestMethod.POST)
 public String saveContact(@ModelAttribute("contact") Contact contact, BindingResult errors, HttpServletRequest request, HttpServletResponse response) {
               ...
            }
        }

How does Spring provide reference to BindingResult, HttpServletRequest, HttpServletResponse objects and any other Spring or Servlet class or interface type that we pass to method as arguments? Does it have a list of default objects that it instantiates on the application start up or does it scans the methods?


Solution

  • When you annotate a controller method with the @RequestMapping, the parameters of the method will be a subject of the argument resolving process. An interface HandlerMethodArgumentResolver and its implementations are at the core of this mechanism. The interface holds two methods supports, and resolveArguments

    In simple terms, all listed arguments are passed through a list of the default resolvers registered with RequestMappingHandlerAdapter (check the getDefaultArgumentResolvers method), if the resolver supports the type, a resolveArgument method is called and an instance is injected as an argument.

    For the four types you've declared, the respective resolvers are

    • ServletModelAttributeMethodProcessor
    • ErrorsMethodArgumentResolver
    • ServletRequestMethodArgumentResolver
    • ServletResponseMethodArgumentResolver

    all registered by default

    Based on argument resolving mechanism, its also quite easy to add a custom resolver, that will instantiate and inject any custom type as well