【Spring框架/笔记】SpringMvc源码解析(二)

一、springMvc执行流程

注:请求-》DispatcherServlet(前端控制器)-》HandlerMapping(找到处理器映射器)-》返回映射器的映射地址url-》handlerAdapter(找到处理器适配器)-》Hanlder(找到处理器)-》找到Controller-》进入service层-》dao层-》返回数据结果一直到DispatcherServlet-》ViewResolver(将数据绑定在ModelAndView传给视图解析器)-》返回View(页面路径)-》DispatcherServlet(渲染视图)-》响应客户端

1、JSP

  • JSP本质上是一个servlet组件
  • 原生的Servlet响应网页给客户端,就需要不断地PrintWriter或println()去渲染。
  • 将HTML抽离出来,定义在其他文件中,在动态的拼接渲染给客户端。
  • JSP可以直接定义网页的代码结构,可以通过El表达式JSTL标签库在实现页面的动态数据加载。
  • Tomcat在编译jsp(xxx.jsp)文件的时候,会将JSP转化为Servlet组件,(xxx_jsp.java源文件)-》
    (xxx_jsp.class)

2、springmvc-servlet.xml(配置文件)

默认读取路径 /WEB-INF/springmvc-servlet.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--    注册处理器映射器
        将一个url地址跟spring容易当中的一个bean的name属性进行匹配
        说明,没有定义id的时候,spring容器会自动定义一个id的值。
        命名规则:包名.类名#自增数字 例如:id=com.xx.jj.controller.xxxController#1
    -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
    <!--    注册处理器(Controller类)
       name属性: 对应的一个前端请求,取值必须使用/开头
       class属性: DispatcherServlet发送过来的请求地址所对应的处理器(controller)
    -->
    <bean class="com.test.controller.DiyController" name="/diy"></bean>
    <!--    配置处理器适配器 HandlerAdapter 
        根据handlerMapping返回的controller,执行一个匹配规则,找到对应的handler去处理controller
    -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
    <!--  配置视图解析器 ViewResolver 
        根据前缀后缀找到对应的视图文件进行渲染
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!--      资源文件的前缀  -->
        <property name="prefix" value="/WEB-INF/"></property> <!-- 给bean对象的属性配置一个初始化值 -->
    <!--    资源文件的后缀    -->
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

二、DispatcherServlet(前端控制器)源码解析

  • 继承关系:DispatcherServlet继承-》FramworkServlet继承-》HttpServletBean继承-》HttpServlet继承-》GenericServlet-》Servlet接口
  • 主要处理流程 doservice-》doDispatch-》获取处理器执行链-》处理器适配器匹配-》前置过滤器-》执行handler(controller方法)->中置过滤器->渲染视图-》后置过滤器
    在这里插入图片描述
  • 两种加载方式
    • 启动即加载
    • 懒加载
    • 配置方式 (LoadOnStartup 0:懒加载 1:启动即加载)
<!-- 基于xml设置 -->
<load-on-startup>1</load-on-startup>
<!-- 基于类的设置 -->
  DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
  registration.setLoadOnStartup(1);
  • 基于xml配置
  <servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring.xml</param-value>
    </init-param>
<!--    load-on-startup 设置成1 启动即加载 ,不设置则 用到时在加载(懒加载) -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <!-- url映射 -->
  <servlet-mapping>
    <servlet-name>app</servlet-name>
    <url-pattern>/app/*</url-pattern>
  </servlet-mapping>
  • 基于注解(实现WebApplicationInitializer)
    注:【tomcat在启动时候遵守Servlet规范,根据SPI机制去找到ServletContainerInitializer下的SpringServletContainerInitializer,在找到头上注释@HandlesTypes({WebApplicationInitializer.class}) 所有实现类,遍历循环onStartup()方法,则会执行下方的DispatcherServlet的装配流程
    SPI读取
  • 查看源码
// 部分代码
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
    public SpringServletContainerInitializer() {
    }

// webAppInitializerClasses 入参,则是所有WebApplicationInitializer的实现类数组
    public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
        List<WebApplicationInitializer> initializers = new LinkedList();
        Iterator var4;
	// 中间省略..... 
	//执行遍历的实现类的onStartup
	 while(var4.hasNext()) {
                WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
                initializer.onStartup(servletContext);
            }
  • 对应的实现类
//实现webApplicationInitializer将dispatcherServlet进行装配
public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(javax.servlet.ServletContext servletContext) throws ServletException {
    // 创建容器
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(WebConfig.class);

	// 前端控制器管理spring容器
        DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
        // 添加url映射
        ServletRegistration.Dynamic registration = servletContext.addServlet("app",dispatcherServlet);

        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");

    }
}
  • 核心方法 doDispatch()
// servlet提供的一个方法,对不同请求方式进行处理
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
       // ..上方代码省略
        try {
        	//调用了doDispatch()方法,传递了请求和响应对象
            this.doDispatch(request, response);
        } finally {}
       // 代码省略
    }
  • doDispatch() 方法定义
// doDispatch 方法定义 
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        // 创建一个处理器执行链(将来执行的请求流程)
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Exception dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    // 通过 getHandler(request)方法,返回一个处理器执行链对象。
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

					// 处理器是适配器,这里主要找到对应handler的适配器。如:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter等。
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    //处理GET请求
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
					//前置过滤器处理
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    //执行handler(执行controller里面的方法)
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                    //获取视图名
                    this.applyDefaultViewName(processedRequest, mv);
                    //执行中置过滤器
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
                //渲染视图
                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }
  • this.getHandler()源码
// handlerMapptings 作用维护url和controller的映射
 @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();

			// HandlerMapping是 servlet所支持的处理器映射集合。
            while(var2.hasNext()) {
            	//拿到 url映射的Controller 例:/test - testController 的映射关系
                HandlerMapping mapping = (HandlerMapping)var2.next();
                //返回一个处理器执行链
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }
  • mapping.getHandler()的源码
@Nullable
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 获取handler对象,由于类型不统一所以转成 Object
        Object handler = this.getHandlerInternal(request);
        if (handler == null) {
            handler = this.getDefaultHandler();
        }

        if (handler == null) {
            return null;
        } else {
            if (handler instanceof String) {
                String handlerName = (String)handler;
                handler = this.obtainApplicationContext().getBean(handlerName);
            }
            //获取处理器执行链,要根据request和handler对象来获取处理器执行链
            HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Mapped to " + handler);
            } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
                this.logger.debug("Mapped to " + executionChain.getHandler());
            }

			//跨域的配置封装到处理器执行链中
            if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
                CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
                CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
                config = config != null ? config.combine(handlerConfig) : handlerConfig;
                executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
            }

            return executionChain;
        }
    }
  • 查看 this.getHandlerInternal(request)
// 获取一个controller
 @Nullable
    protected abstract Object getHandlerInternal(HttpServletRequest var1) throws Exception;
  • 查看this.getHandlerExecutionChain(handler, request)
 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
 		// 获取处理器执行链的对象
        HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
        //获取过滤器
        Iterator var5 = this.adaptedInterceptors.iterator();

        while(var5.hasNext()) {
            HandlerInterceptor interceptor = (HandlerInterceptor)var5.next();
            // 判断过滤器器是否是这个类型
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
                //匹配路径
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                	//过滤器根据请求做匹配加入到过滤器中
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            } else {
                chain.addInterceptor(interceptor);
            }
        }
        //处理器执行链包含:Interceptor和handler
        return chain;
    }
  • DispatcherServlet前端控制器,经过一系列处理返回一个处理器执行链对象 (HandlerExecutionChain)。在该对象中封装了两部分信息(Interceptor和handler)。之后就都是对请求的处理了。
    **

三、XmlWebApplicationContext源码解析

XmlWebApplicationContext维护了springmvc的核心配置

  • 基于xml文件
  <servlet>
  
  <!-- 不设置contextConfigLocation 默认会去找 app-servlet.xml 的文件 -->
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
    </init-param>
    
<!--    load-on-startup 设置成1 启动即加载 ,不设置则 用到时在加载 -->
    <load-on-startup>1</load-on-startup>
    
  </servlet>
  
  <servlet-mapping>
    <servlet-name>app</servlet-name>
    <url-pattern>/app/*</url-pattern>
  </servlet-mapping>
  
  • 源码
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
	//默认配置信息,读取路径
    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";

    public XmlWebApplicationContext() {
    }

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }

    protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
    }

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
            String[] var3 = configLocations;
            int var4 = configLocations.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String configLocation = var3[var5];
                reader.loadBeanDefinitions(configLocation);
            }
        }

    }

    protected String[] getDefaultConfigLocations() {
        return this.getNamespace() != null ? new String[]{"/WEB-INF/" + this.getNamespace() + ".xml"} : new String[]{"/WEB-INF/applicationContext.xml"};
    }
}
  • XmlWebApplicationContext 读取机制
    优先找/WEB-INF/applicationContext.xml 文件,找不到再去找 如果<servlet-name>app</servlet-name>,则会去找 app-servlet.xml的文件。还找不到,就需要指定配置文件路径,如 contextConfigLocation去指定读取路径。
 <servlet-name>app</servlet-name>
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
   <init-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
   </init-param>

四、HandleMapping(处理器映射器)源码解析

注:HandleMapping接口,负责将request请求找到handler对象及interceptor对象,封装到处理器执行链中(HandlerExecutionChain)中,返回给前端控制器。

  • 提供了两个实现类
    • BeanNameUrlHandlerMapping
      • 作用:根据请求的url和spring容器中定义的bean(如:controller)对象的name属性进行匹配,匹配成功则返回一个handler(处理器对象Controller)。
      • 缺点:多个url映射同个controller,会造成代码冗余,Controller的name不能重复,但bean标签的name值可以重复。
      • xml注册处理器映射器
    <!--    注册处理器映射器
        将一个url地址跟spring容易当中的一个bean的name属性进行匹配
        说明,没有定义id的时候,spring容器会自动定义一个id的值。
        命名规则:包名.类名#自增数字 例如:id=com.xx.jj.controller.xxxController#1
    -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
    <!--    注册处理器(Controller类)
       name属性: 对应的一个前端请求,取值必须使用/开头
       class属性: DispatcherServlet发送过来的请求地址所对应的处理器(controller)
    -->
    <bean class="com.test.controller.DiyController" name="/diy"></bean>
  • 源码
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
    public BeanNameUrlHandlerMapping() {
    }

	//根据beanName找到
    protected String[] determineUrlsForHandler(String beanName) {
    	//存储name属性值的集合
        List<String> urls = new ArrayList();
        // 判断Name取值是否以/开头。
        if (beanName.startsWith("/")) {
        	// 将beaanName添加到集合中
            urls.add(beanName);
        }

		//bean的别名也符合条件也加入到集合当中
        String[] aliases = this.obtainApplicationContext().getAliases(beanName);
        String[] var4 = aliases;
        int var5 = aliases.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String alias = var4[var6];
            if (alias.startsWith("/")) {
                urls.add(alias);
            }
        }

        return StringUtils.toStringArray(urls);
    }
}

  • SimpleUrlHandlerMapping

    • 配置方式一
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <!--    通过mappings的属性来配置多个url的请求映射    -->
        <property name="mappings">
        <!-- 是map集合 -->
            <props>
                <!-- 声明一组url的映射,prop标签的内容是bean对象的id取值 -->
                <prop key="/hello">diyController</prop>
                <prop key="/word">diyController</prop>
            </props>
        </property>
    </bean>
    
      <bean class="com.test.controller.DiyController" name="/diy" id="diyController"></bean>
  • 配置方式二
  <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!--        方式二:通过urlMap属性来实现映射 -->
        <property name="urlMap">
            <map>
<!--                entry 表示一组url的 映射 key表示请求的url value表示bean的id值  -->
                <entry key="/hello" value="diyController" ></entry>
            </map>
        </property>
    </bean>
    <bean class="com.test.controller.DiyController" name="/diy" id="diyController"></bean>
  • 源码解析
@Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
        	// 遍历handlerMapping对象
            Iterator var2 = this.handlerMappings.iterator();
            while(var2.hasNext()) {
            	//获取一个handlerMapping对象
                HandlerMapping mapping = (HandlerMapping)var2.next();
                // 通过request获取handlerMapping的处理器执行链
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

getHandler在AbstractHandlerMapping实现了该方法

@Nullable
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    	//根据请求对象获取到handler处理器
        Object handler = this.getHandlerInternal(request);
        if (handler == null) {
            handler = this.getDefaultHandler();
        }

        if (handler == null) {
            return null;
        } else {
            if (handler instanceof String) {
                String handlerName = (String)handler;
                handler = this.obtainApplicationContext().getBean(handlerName);
            }

			//通过Handler和request获取到处理器执行链(包含过滤器和handler)
            HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Mapped to " + handler);
            } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
                this.logger.debug("Mapped to " + executionChain.getHandler());
            }

            if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
                CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null;
                CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
                config = config != null ? config.combine(handlerConfig) : handlerConfig;
                executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
            }

            return executionChain;
        }
    }

五、HandlerAdapter(处理器适配器)源码解析

  • HandlerAdapter执行过程
    DispatcherServlet会根据HandlerMapping返回的handler(Controller)注册到已配置的HandlerAdapter上,HandlerAdapter会根据handler类型来判断是否满足要求,满足要求就返回一个handlerAdapter给DispatcherServlet去执行handler里面的请求体(如SimpleControlerAdapter,则执行的是 handleRequest方法)。

  • 查看doDispatch()中的this.getHandlerAdapter()方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
					//...省略
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                    //...省略
        }
    }
  • getHandlerAdapter()方法
	//通过Handler对象,返回一个handlerAdapter对象
 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        //handlerAdapters 适配器集合
        if (this.handlerAdapters != null) {
        	
            Iterator var2 = this.handlerAdapters.iterator();
            while(var2.hasNext()) {
            	//获取集合中的handlerAdapter对象
                HandlerAdapter adapter = (HandlerAdapter)var2.next();
                //调用handlerAdapter的supports方法
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }

        throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }
  • 查看 supports()方法拥有5个实现类
    在这里插入图片描述
  • 查看SimpleControllerHandlerAdapter的实现
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    public SimpleControllerHandlerAdapter() {
    }

	//判断Handler是否是Controller类
    public boolean supports(Object handler) {
        return handler instanceof Controller;
    }

	// 执行handler里的请求体即 Controller里面的方法 
    @Nullable
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return ((Controller)handler).handleRequest(request, response);
    }
	//与 HttpServlet的getLastModified()方法的约定时间
    public long getLastModified(HttpServletRequest request, Object handler) {
        return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
    }
}

  • handleRequest()执行的方法
//@Component("/test")
public class BeanNameController implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("123",1);
        System.out.println("你好");
        return null;
    }
}

六、ViewResolver(视图解析器)源码解析

  • 执行流程
    1.将SpringMvc的前端控制返回的结果封装成ModelAndView对象。
    2.在通过视图解析器对ModelAndView对象进行解析,解析成一个物理地址映射的视图。
    3.将这个物理地址的视图通过view接口来进行渲染。
  • xml配置
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!--      资源文件的前缀  -->
        <property name="prefix" value="/WEB-INF/"></property> <!-- 给bean对象的属性配置一个初始化值 -->
    <!--    资源文件的后缀    -->
        <property name="suffix" value=".jsp"></property>
    </bean>
  • 源码
public class InternalResourceViewResolver extends UrlBasedViewResolver {
	//加载JSTL的标签库来解析目标JSP文件
    private static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config", 
    // 获取当前类的类加载器
    InternalResourceViewResolver.class.getClassLoader());
    @Nullable
    private Boolean alwaysInclude;

    public InternalResourceViewResolver() {
        Class<?> viewClass = this.requiredViewClass();
        if (InternalResourceView.class == viewClass && jstlPresent) {
            viewClass = JstlView.class;
        }

        this.setViewClass(viewClass);
    }

    public InternalResourceViewResolver(String prefix, String suffix) {
        this();
        this.setPrefix(prefix);
        this.setSuffix(suffix);
    }

    protected Class<?> requiredViewClass() {
        return InternalResourceView.class;
    }

    public void setAlwaysInclude(boolean alwaysInclude) {
        this.alwaysInclude = alwaysInclude;
    }

	//构建页面视图
    protected AbstractUrlBasedView buildView(String viewName) throws Exception {
        InternalResourceView view = (InternalResourceView)super.buildView(viewName);
        if (this.alwaysInclude != null) {
            view.setAlwaysInclude(this.alwaysInclude);
        }

        view.setPreventDispatchLoop(true);
        return view;
    }
}

  • UrlBasedViewResolver 类
public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {

	//重定向的标识
    public static final String REDIRECT_URL_PREFIX = "redirect:";
    //请求转发表示
    public static final String FORWARD_URL_PREFIX = "forward:";
    @Nullable
    private Class<?> viewClass;
    private String prefix = ""; //目标视图的前缀
    private String suffix = ""; //目标视图的后缀
    /...
   }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AloneLie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值