zoukankan      html  css  js  c++  java
  • SpringMVC 学习 十六 中初始化视图解析器过程

    一、SpringMVC简单配置

    我们现在看一段SpringMVC的配置代码,在这段SpringMVC配置文件中,简单配置一些信息,不配置视图解析器。

    <?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
        <mvc:annotation-driven></mvc:annotation-driven>
        <context:component-scan base-package="com.*"></context:component-scan>
    
    
    
        <!-- <mvc:resources mapping="" location=""></mvc:resources>-->
        <mvc:default-servlet-handler></mvc:default-servlet-handler>
    
       
    
    
    </beans>

    然后再写一个简单的处理器

    @RequestMapping("/param02")
        public String param02(User user){
            System.out.println(user);
            System.out.println(user.getPermission().size());
            System.out.println(user.getIds().length);
            return "index.jsp";
        }

    我们发现SpringMVC是可以去项目根目录下找index.jsp文件,但是我们并没有再SpringMVC配置文件中配置VeiwResolver。这是什么原因呢?

    先说结论:是因为在spring-webmvc包里面有一个配置文件DispatcherServlet.properties,这个配置文件中有SpringMVC 的DispatcherServlet中需要的一些属性。

    二、DispatcherServlet.properties

    DispatcherServlet.properties文件内容如下:

    # Default implementation classes for DispatcherServlet's strategy interfaces.
    # Used as fallback when no matching beans are found in the DispatcherServlet context.
    # Not meant to be customized by application developers.
    
    org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
    
    org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
    
    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,
    	org.springframework.web.servlet.function.support.RouterFunctionMapping
    
    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
    	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,
    	org.springframework.web.servlet.function.support.HandlerFunctionAdapter
    
    
    org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,
    	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,
    	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
    
    org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
    
    org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
    
    org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

     在这个配置文件中配置了DispatcherServlet所需要的所有组件

    三、DispatcherServlet需要初始化的组件

    在DispatcherServlet中源码中,DispatcherServlet类中的属性包含了这个前端控制器所需要的视图解析器等组件

    
    	/** MultipartResolver used by this servlet. */
    	@Nullable
    	private MultipartResolver multipartResolver;
    
    	/** LocaleResolver used by this servlet. */
    	@Nullable
    	private LocaleResolver localeResolver;
    
    	/** ThemeResolver used by this servlet. */
    	@Nullable
    	private ThemeResolver themeResolver;
    
    	/** List of HandlerMappings used by this servlet. */
    	@Nullable
    	private List<HandlerMapping> handlerMappings;
    
    	/** List of HandlerAdapters used by this servlet. */
    	@Nullable
    	private List<HandlerAdapter> handlerAdapters;
    
    	/** List of HandlerExceptionResolvers used by this servlet. */
    	@Nullable
    	private List<HandlerExceptionResolver> handlerExceptionResolvers;
    
    	/** RequestToViewNameTranslator used by this servlet. */
    	@Nullable
    	private RequestToViewNameTranslator viewNameTranslator;
    
    	/** FlashMapManager used by this servlet. */
    	@Nullable
    	private FlashMapManager flashMapManager;
    
    	/** List of ViewResolvers used by this servlet. */
    	@Nullable
    	private List<ViewResolver> viewResolvers;
    

    四、初始化视图解析器

    initStrategies方法

     这写组件的初始化在DispatcherServlet的initStrategies方法中

    
    	/**
    	 * Initialize the strategy objects that this servlet uses.
    	 * <p>May be overridden in subclasses in order to initialize further strategy objects.
    	 */
    	protected void initStrategies(ApplicationContext context) {
    		initMultipartResolver(context);
    		initLocaleResolver(context);
    		initThemeResolver(context);
    		initHandlerMappings(context);
    		initHandlerAdapters(context);
    		initHandlerExceptionResolvers(context);
    		initRequestToViewNameTranslator(context);
    		initViewResolvers(context);
    		initFlashMapManager(context);
    	}

    initViewResolvers方法

    DispatcherServlet需要初始化的内容太多,这里只对视图解析的初始化过程进行分析。视图解析的初始化是在initViewResolvers方法中进行的

    /**
    	
         初始化DispatcherServlet使用的视图解析器,如果在BeanFactory中没有视图解析器,则把视图解析器默认设置成InternalResourceViewResolver
         
    	 */
    	private void initViewResolvers(ApplicationContext context) {
    		this.viewResolvers = null;
    
    		// 当detectAllViewResolvers的默认值为true,就是找出所有的视图解析器,
    		if (this.detectAllViewResolvers) {
    			// 在ApplicationContext中查找所有ViewResolver,包括祖先上下文。
                //如果在SpringMVC的配置文件以及Spring的配置文件中都没有配置,则在两个上下文中都找不到视图解析器
    			Map<String, ViewResolver> matchingBeans =
    					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
    			if (!matchingBeans.isEmpty()) {
    				this.viewResolvers = new ArrayList<>(matchingBeans.values());
    				// We keep ViewResolvers in sorted order.
    				AnnotationAwareOrderComparator.sort(this.viewResolvers);
    			}
    		}else {
            	//当detectAllViewResolvers为false时, 
    			try {
    				ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
    				this.viewResolvers = Collections.singletonList(vr);
    			}
    			catch (NoSuchBeanDefinitionException ex) {
    				// Ignore, we'll add a default ViewResolver later.
    			}
    		}
    
    		/**
            Ensure we have at least one ViewResolver, by registering
    		 a default ViewResolver if no other resolvers are found.
             要确保必须最少有一个视图解析器,如果在SpringMVC上下文以及Spring上下文中都没有,则调用getDefaultStrategies
             创建默认的视图解析器
             */
    		if (this.viewResolvers == null) {
    			this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No ViewResolvers declared for servlet '" + getServletName() +
    						"': using default strategies from DispatcherServlet.properties");
    			}
    		}
    	}

    getDefaultStrategies方法

    getDefaultStrategies方法会返回默认的视图解析器

    
    	/**
    	 * Create a List of default strategy objects for the given strategy interface.
    	 * <p>The default implementation uses the "DispatcherServlet.properties" file (in the same
    	 * package as the DispatcherServlet class) to determine the class names. It instantiates
    	 * the strategy objects through the context's BeanFactory.
    	 * @param context the current WebApplicationContext
    	 * @param strategyInterface the strategy interface
    	 * @return the List of corresponding strategy objects
    	 */
    	@SuppressWarnings("unchecked")
    	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    		if (defaultStrategies == null) {
    			try {
    				// Load default strategy implementations from properties file.
    				// This is currently strictly internal and not meant to be customized
    				// by application developers.
    				ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
    				defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    			}
    			catch (IOException ex) {
    				throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
    			}
    		}
    
    		String key = strategyInterface.getName();
    		String value = defaultStrategies.getProperty(key);
    		if (value != null) {
    			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
    			List<T> strategies = new ArrayList<>(classNames.length);
    			for (String className : classNames) {
    				try {
    					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
    					Object strategy = createDefaultStrategy(context, clazz);
    					strategies.add((T) strategy);
    				}
    				catch (ClassNotFoundException ex) {
    					throw new BeanInitializationException(
    							"Could not find DispatcherServlet's default strategy class [" + className +
    							"] for interface [" + key + "]", ex);
    				}
    				catch (LinkageError err) {
    					throw new BeanInitializationException(
    							"Unresolvable class definition for DispatcherServlet's default strategy class [" +
    							className + "] for interface [" + key + "]", err);
    				}
    			}
    			return strategies;
    		}
    		else {
    			return Collections.emptyList();
    		}
    	}

    上面的代码的意思是:

    注意通过initViewResolvers 调用getDefaultStrategies,传递过来的参数是WebApplicationContext类型的变量和一个ViewResolver.class类型的变量。

      

    1. 先判断defaultStrategies是不是为空,如果为空,则把DispatcherServlet.properties中的内容加载到defaultStrategies中
    2. 根据入参ViewResolver.class的名称,获取defaultStrategies的值,获取的值就是"org.springframework.web.servlet.view.InternalResourceViewResolver"
    3. 然后就根据上面获取的全路径名创建InternalResourceViewResolver实例,并放入一个列表中返回。

    createDefaultStrategy方法

    在getDefaultStrategies中调用createDefaultStrategy来创建需要的视图解析器,

    createDefaultStrategy方法中通过AutowireCapableBeanFactory接口的实现类AbstractAutowireCapableBeanFactory中的createBean方法创建视图解析器。

    	protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
    		return context.getAutowireCapableBeanFactory().createBean(clazz);
    	}
    

    createBean方法

    	//-------------------------------------------------------------------------
    	// Typical methods for creating and populating external bean instances
    	//-------------------------------------------------------------------------
    
    	@Override
    	@SuppressWarnings("unchecked")
    	public <T> T createBean(Class<T> beanClass) throws BeansException {
    		// Use prototype bean definition, to avoid registering bean as dependent bean.
    		RootBeanDefinition bd = new RootBeanDefinition(beanClass);
    		bd.setScope(SCOPE_PROTOTYPE);
    		bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
    		return (T) createBean(beanClass.getName(), bd, null);
    	}

    就如注释中所说的,这个createBean是用来建和填充外部bean实例的,我们从代码中也可以看到,这个方法创建的bean的作用域都是prototype的。是不会注入到Spring容器中的。

    五、总结

    DispatcherServlet初始化视图解析器的过程如下:

    首选从SpringMVC容器或者Spring容器中获取,如果获取到了就直接把获取到的视图解析器赋值给DispatcherServlet的viewResolvers属性。

    如果获取不到就根据配置文件DispatcherServlet.properties配置的视图解析器来创建,创建好的视图解析器不会注册到Spring容器,会直接返回,然后赋值给DispatcherServlet的viewResolvers属性。

  • 相关阅读:
    IIS7中的几种身份鉴别方式(一)Basic身份验证
    IIS7中的几种身份鉴别方式(二)集成身份验证
    java集合
    SharePoint 2010中welcome page的设置细节
    SharePoint中使用Linq出现未将对象引用到实例化的解决方法
    SharePoint 2010中关于An error was encountered while retrieving the user profile的处理方式记录
    The Need for an Architectural Body of Knowledge
    The Softer Side of the Architect
    Event Receivers 学习小结
    使用SmtpClient发送带图片的邮件的代码实现
  • 原文地址:https://www.cnblogs.com/cplinux/p/15418352.html
Copyright © 2011-2022 走看看