A list,

Spring MVC is a lightweight Web framework based on Java that implements the request-driven type of MVC design pattern. By separating Model, View and Controller, the Web layer decouplesresponsibilities, and divides complex Web applications into several logically clear parts, simplifying development and reducing errors. Facilitate collaboration between developers within the group.

1. Advantages of Springmvc:

  1. Support for a variety of view technologies, not just JSPS;

  2. Integration with the Spring framework (such as IoC container, AOP, etc.);

  3. Clear role assignment: front-end controller (dispatcherServlet), request-to-handler mapping (HandlerAdapter), ViewResolver (ViewResolver).

  4. Supports mapping strategies for various requested resources.

2. Request mapper source code parsing

These features make it more than 98% used in enterprise development. Have you ever wondered how SpringMvc intercepts and handles a request once it arrives?

I believe you are familiar with the above flow chart, more or less whether it is preparing for the interview, or their own learning, will be exposed to this flow chart, I have seen a lot of people, to this figure by rote memorization! I have also interviewed some technical personnel, asked about this knowledge, raised his head and closed his eyes (exaggerate) to say this knowledge, and then asked a little deeper on the ignorant force, in the final analysis is not deep enough to understand the framework.

I. How does SpringMVC perceive the URL path corresponding to each method?

Org. Springframework. Web. Servlet. Handler. AbstractHandlerMethodMapping implementation Org. Springframework. Beans. Factory. Cover the afterPropertiesSet InitializingBean method, this method will be at the time of the Spring container initialization callback the method

The method class is defined as

@Override
public void afterPropertiesSet(a) {
    initHandlerMethods();
}
Copy the code

Call initHandlerMethods, so what’s going on in initHandlerMethods? Step by step analysis of this method!

/**
 * Scan beans in the ApplicationContext, detect and register handler methods.
 * @see #getCandidateBeanNames()
 * @see #processCandidateBean
 * @see #handlerMethodsInitialized
 */
protected void initHandlerMethods(a) {
    for (String beanName : getCandidateBeanNames()) {
        if(! beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { processCandidateBean(beanName); } } handlerMethodsInitialized(getHandlerMethods()); }Copy the code

First, the getCandidateBeanNames() method, let’s look at its definition

/**
 * Determine the names of candidate beans in the application context.
 * @since 5.1
 * @see #setDetectHandlerMethodsInAncestorContexts
 * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors
 */
protected String[] getCandidateBeanNames() {
    return (this.detectHandlerMethodsInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
            obtainApplicationContext().getBeanNamesForType(Object.class));
}
Copy the code
  • The essence of this method is to get all of the beans out of the bean container. Why get all of them because it’s based onObject.classThis method can fetch all the beans in the Spring container and then return them!

After initHandlerMethods() gets all the beans and loops through, we focus on the processCandidateBean method inside the body of the loop

protected void processCandidateBean(String beanName) { Class<? > beanType =null;
    try {
        beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
        // An unresolvable bean type, probably from a lazy bean - let's ignore it.
        if (logger.isTraceEnabled()) {
            logger.trace("Could not resolve type for bean '" + beanName + "'", ex); }}if(beanType ! =null&& isHandler(beanType)) { detectHandlerMethods(beanName); }}Copy the code
  • beanType = obtainApplicationContext().getType(beanName);

    • This method gets the Class object of the bean based on its name
  • isHandler(beanType)

    • This method is to determine whether the class is annotatedControllerComments orRequestMapping
@Override
protected boolean isHandler(Class
        beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
    AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
Copy the code
  • detectHandlerMethods(Object handler)
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup<T>) method -> {
    try {
    return getMappingForMethod(method, userType);
    }
    catch (Throwable ex) {
        throw new IllegalStateException("Invalid mapping on handler class [" +
                                        userType.getName() + "]."+ method, ex); }});Copy the code

This internal logic iterates through all methods of a class

  • getMappingForMethod(method, userType); What’s going on inside this method?

    This I party internally reads all definitions of all mapping methods, with the following logic

Set the method mapping path, method object, method parameters, set method request header, consumption type, acceptable type, mapping name and other information encapsulated in the RequestMappingInfo object return!Copy the code
  • getPathPrefix(handlerType);

    This method is used to handle method prefixes if there is a merge with the former method level

  • RequestMappingInfo = RequestMappingInfo = RequestMappingInfo = RequestMappingInfo = RequestMappingInfo

    • Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); Find the proxy method for that method!
    • registerHandlerMethod(handler, invocableMethod, mapping); Register the method!
      • Let’s dive into this method and throw out all the other code that’s not relevant to this article, and here’s what we find!

We will find that the url annotated on our method and the previous reading of the method definition bound in a method called urlLookup, please remember this method, this method is useful for our understanding of SpringMvc processing logic!

3. Request logical source code parsing

Now all the corresponding @requestMapping methods in the whole project have been cached, take this method as an example!

@RestController
public class TestController {

    @RequestMapping("test")
    public String test(a){
        return "success"; }}Copy the code

UrlLookup = test(); urlLookup = test();

The key central class DispatcherServlet is actually a subclass of Servlet. Those of you familiar with servlets know that in Servlet development, all requests are configured to be intercepted by the internal doget and Dopost methods. So why SpringMvc can intercept the URL is not difficult to analyze, after intercepting the URL, enter the following process call chain!

Request via org. Springframework. Web. Servlet. FrameworkServlet# doGet capture, Entrusted to org. Springframework. Web. Servlet. FrameworkServlet# the processRequest method, Finally in the calling org. Springframework. Web. Servlet. DispatcherServlet# doService to deal with the real logic!

Let’s take a look at some of the main logic behind this method.

Org. Springframework. Web. Servlet. DispatcherServlet# doDispatch call org. Springframework. Web. Servlet. DispatcherServlet# getHandl Er method, Called again org. Springframework. Web. Servlet. Handler. AbstractHandlerMapping# getHandler via org. Springframework. Web. Servlet. Handler. A BstractHandlerMethodMapping# getHandlerInternal method of org. Springframework. Web. Servlet. Handler. AbstractHandlerMethodMapping# lo OkupHandlerMethod of org. Springframework. Web. Servlet. Handler. AbstractHandlerMethodMapping. MappingRegistry# getMappingsByUrl speak Too long call chain is not meng, at this time we finally see the main!

/**
 * Return matches for the given URL path. Not thread-safe.
 * @see #acquireReadLock()
 */
@Nullable
public List<T> getMappingsByUrl(String urlPath) {
    return this.urlLookup.get(urlPath);
}
Copy the code

Is this code familiar? This is the property where we put the URL and method definition in the Spring container during initialization, and now the Spring container intercepts the request via DispatcherServlet and finds the method again and returns!

This completes the HandlerMapping part of the MVC flowchart.

Request about the mapping of the source code analysis in this chapter to this will be over, follow-up, the author will deal with the adapter, processors, view the parser to explain, subsequent logic is actually very simple, simple, after obtaining method reflection to execute the method, it is not certain, general scenario, then get a return value, Determine if there is an @responseBody annotation, determine if it needs to be converted to JSON, and then write back to the page! General process is such, detailed process author will write later!

After today’s process analysis, can you write your own SpringMvc based on servlets?


If the understanding of the article is wrong, welcome big men private chat correction! Welcome to pay attention to the author’s public number, progress together, learn together!