Pretend to look at the source code of springmvc (3) view analysis of springmvc

View resolution of springmvc

Overview: The view resolution of springmvc is mainly to build the View through ViewResolver, then assemble the model data, and finally render the view. The ViewResolver is configured by us. The default ViewResolver provided is the InternalResourceViewResolver or Jsp view. Below we find the principle of view resolution in the source code. And realization.

One, ViewResolver analysis

Springmvc view resolution is to query the specified view through ViewResolver according to the name of the view, while View replicates and renders, and Resolver replicates to find the specified view. By default, the configured ViewResolver is InternalResourceViewResolver , and the view queried corresponding to InternalResourceViewResolver is a subclass of InternalResourceView JstlView .class.

1. Inheritance structure of ViewResolver

        ViewResolver top-level interface
            + View resolveViewName(String viewName, Locale locale)


        AbstractCachingViewResolver cache abstract base class---The main function is View object plus cache access processing
            + View resolveViewName(String viewName, Locale locale) // cache processing, internal call createView() to create view
            View createView(String viewName) // create view Method, directly call loadView to create a view
            abstract View loadView(String viewNmae) // Abstract method-subclass to implement
        
        UrlBasedViewResolver  Url parsing basic implementation class-the main function is to deal with redirect and forword, and create View according to class to set url
            View createView( String viewName) // After copying the parent class to add parsing redirect and forword processing, call the createView method of the parent class again.
            View loadView(String viewName) // Mainly call buildView to implement
            View buildView(String viewName) // Mainly create view instance based on getViewClass, and must be a subclass of AbstractUrlBasedView
        
        InternalResourceViewResolverInherit UrlBasedViewResolver---process the view resolution of jsp, the function is to provide the base class of getViewClass()
        
        AbstractTemplateViewResolver template view resolution--- mainly overwrite buildView and restrict the getViewClass type and public settings
            View buildView(String viewName) // override buildView , And after calling the buildView of the parent class, limit the subclass
        
        FreeMarkerViewResolver of AbstractTemplateView to inherit AbstractTemplateViewResolver---the function is to provide ViewClass() of FreeMarker

2. Class diagram and introduction

3. The main code snippets of ViewResolver

        1) The resolveViewName method implemented by AbstractCachingViewResolver

         For details, please see: https://blog.csdn.net/shuixiou1/article/details/113006428  

        2) The createView method of UrlBasedViewResolver resolves redirect and forward.

         protected View createView(String viewName, Locale locale) throws Exception {
			if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
				String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
				RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
				return applyLifecycleMethods(viewName, view);
			}
			if (viewName.startsWith(FORWARD_URL_PREFIX)) {
				String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
				return new InternalResourceView(forwardUrl);
			}
			// 调用父类createView,实际调用模板方法loadView由本类是实现,再调用buildView
			return super.createView(viewName, locale);
		}

     3) UrlBasedViewResolver's buildView method

protected AbstractUrlBasedView buildView(String viewName) throws Exception {
			AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());  // 根据viewClass创建View
			view.setUrl(getPrefix() + viewName + getSuffix()); // 设置url
	
			String contentType = getContentType();
			if (contentType != null) {
				view.setContentType(contentType);
			}
			// .....略
			return view;
		}

    4) Setting viewClass of InternalResourceViewResolver and FreeMarkerViewResolver

public InternalResourceViewResolver() { // 构造函数设置ViewClass
				Class<?> viewClass = requiredViewClass();
				if (viewClass.equals(InternalResourceView.class)) {
					viewClass = JstlView.class;
				}
				setViewClass(viewClass);
			}
			protected Class<?> requiredViewClass() { // 提供InternalResourceView视图
				return InternalResourceView.class;
			}
			public FreeMarkerViewResolver() { // 构造函数设置ViewClass
				setViewClass(requiredViewClass());
			}
			protected Class<?> requiredViewClass() { // 提供FreeMarkerView的视图
				return FreeMarkerView.class;
			}

Two, View class analysis

1. Overview : From the analysis of ViewResolver above, we can know that when ViewResolver gets the view, it has created an instance of the view, processed redirect and forword requests, and set the url. Now if you want to render the page, you only need to put the model's Combine data and views, and then render the page.
      The type of View and ViewResolver appear correspondingly, and the final ViewResolver specifies the specific View type. Let's look at the inheritance structure of View first.

2. View class structure

        View view interface
             + void render(model, request, response)

        AbstractView abstract base class
            + void render(model, request, response) // The realization of render is mainly the merging of some model data, calling the template method renderMergedOutputModel
            abstract renderMergedOutputModel() // After the model data is merged, the template method for performing rendering is implemented by the subclass .
            
        AbstractUrlBasedView abstract base class --- Provides the view implementation of Url built-in property  
        
        InternalResourceView JSP --- Forward the request to jsp
            + renderMergedOutputModel() // Model data is added to requestAttr, RequestDispatcher forwards the request to the jsp page

        RedirectView redirection operation with view packaging ---- mainly redirection and parameter processing and processing FlashMap
            + renderMergedOutputModel() // Redirection parameter processing and FlashMap processing.

  3.
   The renderMergedOutputModel() method of the source code fragment InternalResourceView

   protected void renderMergedOutputModel(
                Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
                
                exposeModelAsRequestAttributes(model, request); // model参数到requestAttr
                String dispatcherPath = prepareForRendering(request, response); // 路径处理
                RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); // request.getRequestDispatcher(path);
                rd.forward(request, response); // 转发
            }

Three, process analysis

After understanding the basic functions and class structure of ViewResolver and View, you basically know that spring-mvc view resolution is a corresponding view resolver. The process of creating a corresponding type of view based on the view name. This process handles the caching and redirection of the view. And forword, and will eventually assemble model parameters, or process a series of operations such as redirecting FlashMap parameters to session.

Let's take a look at the view analysis of springmvc against the source code during execution.

3.1 First , let's first look at how the view resolver ViewResolver is initialized, that is, how springmvc determines the type of view resolver according to what springmvc determines the type of view resolver, directly cut into the topic, we go to the spring-mvc core servlet-DispatcherServlet to initialize ViewResolver to view.

	private void initViewResolvers(ApplicationContext context) {
		this.viewResolvers = null;

		if (this.detectAllViewResolvers) {
			// 从spring容器查询所有的ViewResolvers
			Map<String, ViewResolver> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values());
				OrderComparator.sort(this.viewResolvers);
			}
		}
		else {
             // 查询一个ViewResolvers
				ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
				this.viewResolvers = Collections.singletonList(vr);
		}
        // 如果没有,就加载默认,默认实际上是DispatcherServlet.properties中配置了
		if (this.viewResolvers == null) {
			this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
			}
		}
	}
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key); // 从配置文件得到指定的key
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			for (String className : classNames) {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); // 获取class,并后续加载到spring容器创建bean
                // .........
            }

    }
		
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

 The above is the default view resolver specified by DispatcherServlet.properties

3.2 Actual tracking request process

First create a Controller


	/**
	 * 基本请求
	 */
	@RequestMapping("/hello")
	public String baseHello(Model model) {
		
		model.addAttribute("param1", "param1");
		model.addAttribute("param2", "param2");
		
		return "/hello";
	}
	
	/**
	 * 重定向请求
	 */
	@RequestMapping("/redirect")
	public String redireHello(Model model) {
		
		return "redirect:/hello";
	}

Process omitted...

complete! ! !

 

 

 

Guess you like

Origin blog.csdn.net/shuixiou1/article/details/113007614