Deep analysis of Spring MVC from the perspective of source code

Spring MVC has a clear division of roles, detailed division of labor, and seamless integration with the Spring framework. Spring MVC has become one of the current most mainstream frameworks. And with the release of Spring3.0, it surpassed Struts2 to become the best MVC framework.

But many developers only know how to write, but don't know why they write this way or how to optimize, which is very dangerous. And based on my many years of experience, Spring MVC's problems are high-frequency inspection points that appear during the interview process, and major manufacturers pay more attention to the source code analysis of developers.

I share one here. There are a lot of dry goods, including detailed explanations on jvm, netty, spring, threads, spring cloud, etc., as well as detailed study planning diagrams, interview questions, etc. I feel that the interview is very clear: Get an interview Information only: Click here to receive!!! Password: CSDNInsert picture description here

Many big companies will ask: How much do you know about the Spring MVC source code? Do you have source code analysis capabilities?
For example, the following two contents:
What is the request processing flow of Spring MVC?
Insert picture description here

The ha.handle method in the Spring MVC framework

Entrance
Insert picture description here

From the mouth into the break Insert picture description here
Insert picture description here
as a developer, source framework grasp the depth of analysis capabilities is particularly important in the interview and work. If you can only use the framework, then you can only do some simple back-end systems (business-level systems), you can never do department-level, company-level, and Apache-level projects.

working principle

The user sends a request to the DispatcherServlet front controller provided by the springMVC framework (friends who know Struts2 also know that in fact, Struts2 also has a front controller, the Filter tag in web.xml)

The front controller will go to the processor to mapper (HandlerMapping), the processor mapper finds the specific processor according to the request URL, generates the processor object and the processing interceptor (if any) and returns it to the DispatcherServlet.

According to the processor returned by the processor mapper, DispatcherServlet will find a "suitable" processor adapter (HandlerAdapter)

The processor adapter HandlerAdapter will execute the processor (when the Handler is developed, it will be called the controller or the front-end controller, and the action in struts2 is also a back-end controller) before execution, there will be converters, data binding, validators, etc. Wait until the above is completed before going back to execute

Handler

The back-end controller Handler returns a ModelAndView object after the execution is complete. The
processor adapter HandlerAdapter returns this ModelAndView to the front-end controller DispatcherServlet. The front-end controller will give the ModelAndView object to the view resolver ViewResolver
ViewResolver parses the ModelAndView object and returns the logic View. The
front controller DispatcherServlet renders the logical view (fills in data) and then returns the real physical View and responds to the browser.
Component description

DispatcherServlet: Front Controller

The user request arrives at the front controller, which is equivalent to C in MVC, and the DispatcherServlet is the core of the entire process.It calls other components to process user requests.The existence of the front controller reduces the coupling between other components.

HandlerMapping: Handler Mapper

Its function is like going to a movie, holding a movie ticket to find the seat on the seat according to the seat number on the movie ticket, where the seat is the Handler, and the movie ticket and the seat number on it are the URL.

HandlerMapping is responsible for finding the Handler that is the processor according to the user's request.SpringMVC provides different mappers to implement different mapping methods, such as: configuration file method, implementation interface method, annotation method, etc.

Handler: Handler

Handler is a back-end controller. The back-end controller processes specific user requests under the control of the front controller. Handler involves specific user requests, so in general, programmers are required to develop according to their own business.

HandlerAdapter: processor adapter

The processor is executed through the HandlerAdapter, which is an application of the adapter mode, and more types of processors can be executed through the adapter.

The movie being played is 3D and you can't see clearly. The movie theater tells you that you must wear 3D glasses if you want to see the movie clearly, which means that the Handler meets certain requirements and guesses can be executed.

SpringMVC configuration

The front controller needs to be configured in web.xml

<?xml version="1.0" encoding="UTF-8"?>

<!-- 配置前端控制器 -->
<servlet>
    <servlet-name>web-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加载前端控制器配置文件 上下文配置位置-->
    <init-param>
        <!-- 备注:
            contextConfigLocation:指定 SpringMVC 配置的加载位置,如果不指定则默认加载
            WEB-INF/[DispatcherServlet 的 Servlet 名字]-servlet.xml
         -->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-*.xml</param-value>
    </init-param>
    <!-- 表示随WEB服务器启动 -->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>web-dispatcher</servlet-name>
    <!-- 备注:可以拦截三种请求
        第一种:拦截固定后缀的url,比如设置为 *.do、*.action, 例如:/user/add.action 此方法最简单,不会导致静态资源(jpg,js,css)被拦截
        第二种:拦截所有,设置为/,例如:/user/add  /user/add.action此方法可以实现REST风格的url,
        很多互联网类型的应用使用这种方式.但是此方法会导致静态文件(jpg,js,css)被拦截后不能正常显示.需要特殊处理
        第三种:拦截所有,设置为/*,此设置方法错误,因为请求到Action,当action转到jsp时再次被拦截,提示不能根据jsp路径mapping成功
       -->
        <!-- 默认匹配所有的请求 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

在spring/spring-web.xml配置视图解析器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    <!-- 配置视图解析器 -->
    <!-- InternalResourceViewResolver:支持JSP视图解析 -->
    <!-- viewClass:JstlView 表示JSP模板页面需要使用JSTL标签库,所以classpath中必须包含jstl的相关jar包; -->
    <!-- prefix 和 suffix:查找视图页面的前缀和后缀,最终视图的址为: -->
    <!-- 前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,-->
    <!-- 则最终返回的jsp视图地址 "WEB-INF/jsp/hello.jsp" -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 决定视图类型,如果添加了jstl支持(即有jstl.jar),那么默认就是解析为jstl视图 -->
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <!-- 视图前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 视图后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
在spring/spring-web.xml的注解模式

<!-- 自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter, -->
<!-- 可用在xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。 -->
<mvc:annotation-driven/>
在spring/spring-web.xml 配置扫描web相关的bean

<context:component-scan base-package=“com.controller” />

Annotations in springMVC

@Controller annotation is
used to identify that this class is a back-end controller (similar to struts2 actions), the main function is to receive page parameters and forward the page

@controller source code:

@Target({ElementType.TYPE}) // Indicates that it can only be defined on the class
@Retention(RetentionPolicy.RUNTIME) //The retention policy is RUNTIME. When the JVM loads the class, the annotation will be loaded into the JVM memory (it is the only You can use reflection to read the annotation strategy)
@Documented //@Documented is used to describe that other types of annotations should be used as the public API of the marked program members, so they can be documented by tools such as javadoc. Documented is a mark annotation and has no members.
@Component //The spring framework stipulates that this annotation can be used when a class is not well classified (service, dao, controller), which shows that the @Component annotation is still used even if it is well classified

public @interface Controller {
    
    
    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any
     */
    String value() default "";
}
@RequestMapping

The function of this annotation is different from @Controller.This annotation can be defined on the class or on the method.

/**
* 1.@RequestMapping:除了修饰方法,还可以修饰类
* 2.类定义处:提供初步的请求信息映射.相对于WEB应用的根目录(窄化请求)
* 3.方法处:提供进一步的细分映射信息。相对于类定义处的URL。
*      若类定义处为标注@RequestMapping,则方法出的URL相对于WEB应用的根目录
*/
@Target({
    
    ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    
    
    String[] value() default {
    
    };
    RequestMethod[] method() default {
    
    }; //限制请求方式
    String[] params() default {
    
    }; //要求请求的URL包含指定的参数
}

Code example

@Controller
@RequestMapping("/demo")
public class IndexController {
    
    
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String index(Model model, HttpServletRequest request) {
    
    
        // 在游览器访问 http://localhost:8080/demo/test 将进入这里
        model.addAttribute("originURL", "");
        model.addAttribute("controllerName", "index");
        return "index";
    }
}
@RequestMapping还支持Ant方格的请求
?:匹配文件中的一个字符
*:匹配文件中任意字符
****匹配多层路径
/user/*/createUser : 匹配 -/user/aa/createUser 或者 -/user/aa/createUser
/user/**/createUser : 匹配 -/user/aa/createUser 或者 -/user/createUser 或者 -/user/aa/cc/createUser
/user/createUser?? : 匹配 -/user/aa/createUseraa
@PathVariable

This annotation supports the current more popular Restful style URLs. Let me talk about the role of this annotation first. It supports binding the placeholder parameters in the URL to the parameters on the target method. This function is also an important measure for springMVC to implement the Restful style URL. .

Code

// http://localhost:8080/demo/sss
@RequestMapping(value = "/{slug:.+}", method = RequestMethod.GET)
    public String index2(@PathVariable("slug") String slug, Model model) {
    
    
    LOG.info("DemoController index2 slug  " + slug);
    // common
    model.addAttribute("originURL", "demo/");
    model.addAttribute("controllerName", "demo");
    model.addAttribute("controllerMethod", "index2");
    model.addAttribute("slug", slug);
    return "demo";
}

//slug = sss

The requests we are familiar with should be POST and GET requests. These two requests are also the most commonly used. In fact, http1.1 requests are still put, delete and other 8 types of actions to request by name

To implement put and delete requests in springMVC, you need to configure an additional filter in web.xml.The function of this filter is to change post requests into put and delete requests.

@RequestParam
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
    
    
    String value() default "";//值即为请求参数的参数名
    boolean required() default true;//该参数是否是必须。默认值为true
    String defaultValue() default ValueConstants.DEFAULT_NONE;//请求参数的默认值
}
// http://localhost:8080/demo/para?slug=google
@RequestMapping(value = "/para", method = RequestMethod.GET)
public String index3(@RequestParam(value = "slug", defaultValue = "") String slug, Model model) {
    
    
    model.addAttribute("originURL", "demo/");
    model.addAttribute("controllerName", "demo");
    model.addAttribute("controllerMethod", "index3");
    model.addAttribute("slug", slug);
    return "demo";
}
slug = google

There is another point to remind that the parameter can be mapped successfully without this annotation. This is because the SpringMVC framework supports the request parameter and the target method parameter to be consistent. This annotation can be omitted.

@ResponseBody
/**
 * Annotation that indicates a method return value should be bound to the web
 * response body. Supported for annotated handler methods in Servlet environments.
 * 
 * 这个注解指明一个方法的返回值应该绑定在 web response body 中,在 Servlet 环境中支持注解处理方法
 * 
 * <p>As of version 4.0 this annotation can also be added on the type level in
 * which case it is inherited and does not need to be added on the method level.
 */
@Target({
    
    ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
    
    
}

Code

// http://localhost:8080/demo/json
@RequestMapping(value = "/json", method = RequestMethod.POST)
public @ResponseBody Domain index7(HttpServletRequest request, Model model) {
    
    

    LOG.info("DemoController demo index7");
    model.addAttribute("originURL", "demo/");
    model.addAttribute("controllerName", "demo");
    model.addAttribute("controllerMethod", "index7");

    Domain domain = new Domain();
    domain.setDomain("gggoogle.com");
    domain.setId(100);
    return domain;
}

/* response body
{
    "id": 100,
    "domain": "gggoogle.com"
}
*/

Guess you like

Origin blog.csdn.net/weixin_50917449/article/details/109393345