spring mvc (三)

1、服务器加载DispatcherServlet

        当服务器加载DispatcherServlet时,会加载属性文件【org.springframework.web.servlet】DispatcherServlet.properties

文件内容为:

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.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
	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.java

通过加载默认文件中设置的默认处理类放置到对象 defaultStrategies

	private static final Properties defaultStrategies;

	static {
		// Load default strategy implementations from properties file.
		// This is currently strictly internal and not meant to be customized
		// by application developers.
		try {
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
		}
	}

   当容器初始化WebApplicationContext后将会调用onRefresh来更新应用环境上下文中的相关对象

	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	/**
	 * 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);//需要配置,没有为null
		initLocaleResolver(context);//优先配置,如果没有配置则使用默认配置
		initThemeResolver(context);//优先配置,如没有则使用默认
		initHandlerMappings(context);//优先配置,如没有则使用默认
		initHandlerAdapters(context);//优先配置,如没有则使用默认
		initHandlerExceptionResolvers(context);//优先配置,如没有则使用默认
		initRequestToViewNameTranslator(context);//优先配置,如没有则使用默认
		initViewResolvers(context);//优先配置,如没有则使用默认
		initFlashMapManager(context);//优先配置,如没有则使用默认
	}
 

    A、首先是初始化文件上传的解析器对象,通过id为multipartResolver来注入对象的bean

public class DispatcherServlet extends FrameworkServlet {

	/** Well-known name for the MultipartResolver object in the bean factory for this namespace. */
	public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
	/**
	 * Initialize the MultipartResolver used by this class.
	 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
	 * no multipart handling is provided.
	 */
	private void initMultipartResolver(ApplicationContext context) {
		try {
			this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Default is no multipart resolver.
			this.multipartResolver = null;
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
						"': no multipart request handling provided");
			}
		}
	}

    如果没有这设置为null,因此如果我们需要进行文件上传,要再[servlet-name]-servlet.xml文件中配置

        multipartResolver对应的bean【CommonsMultipartResolver是接口MultipartResolver的实现类】

      然后由他转发到我们对应的Controller

  

<bean id="multipartResolver"  
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
    <!-- 设置上传文件的最大尺寸为1MB -->  
    <property name="maxUploadSize">  
        <value>1048576</value>  
    </property>  
</bean>
 

  单个文件

@RequestMapping("/fileUpload")
public String executeMultipart(MultipartFile file){
   //....
}
多个文件可以如下设参数

@RequestMapping("/fileUpload")
public String executeMultipart(MultipartFile[] files){
   //....
}


    B、  然后就是对国际化bean的初始化 id为:LocaleResolver,处理方式与文件上传相似,但是spring为我们提供了默认

  的处理类(见 DispatcherServlet.properties)

      

  (类似还有RequestToViewNameTranslator 通过id:viewNameTranslator;

           FlashMapManager 通过id:flashMapManager)


	/** Well-known name for the LocaleResolver object in the bean factory for this namespace. */
	public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";

	/**
	 * Initialize the LocaleResolver used by this class.
	 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
	 * we default to AcceptHeaderLocaleResolver.
	 */
	private void initLocaleResolver(ApplicationContext context) {
		try {
			this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
						"': using default [" + this.localeResolver + "]");
			}
		}
	
      提供的默认类AccepHeaderLocaleResolver,源码如下

public class AcceptHeaderLocaleResolver implements LocaleResolver {

	public Locale resolveLocale(HttpServletRequest request) {
		return request.getLocale();
	}

	public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
		throw new UnsupportedOperationException(
		"Cannot change HTTP accept header - use a different locale resolution strategy");
	}

}
  C、Spring MVC支持一个叫主题(theme)的概念,它是Web应用程序可互换的外观。主题也常叫做皮肤(skin),是将界面外观(色彩方案、图标、按钮尺寸等)从用户界面中抽象出来的一种方式。这有助于用户界面的实现,因为皮肤信息可以在运行时被呈现,而不用每种为不同的界面外观每次都要复制每个页面。我们要关注如何针对每位用户的请求来选择和操作主题。这里的概念与LocaleResolver非常相似。

DispatcherServlet不支持多个ThemeResolvers的串连。它会在ApplicationContext中试图找到名为themeResolver的bean。若未找到任何ThemeResolver,那么DispatcherServlet会创建自己的FixedThemeResolver,后者配置为默认值。

   D、然后就是HandlerMapping

/** List of HandlerMappings used by this servlet */
	private List<HandlerMapping> handlerMappings;
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
	private boolean detectAllHandlerMappings = true;
  
	/**
	 * Initialize the HandlerMappings used by this class.
	 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
	 * we default to BeanNameUrlHandlerMapping.
	 */
	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
     //对于HandlerMappings,服务器在启动的时候会先去查找我们在配置文件中配置的处理对象类,如果存在则使用(忽略spring默认配置的)
                if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				OrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}
    E、然后就是HandlerAdapter,与HandlerMapping类似(相同的处理还有:HandlerExceptionResolver/

      ViewResolver/)

	/**
	 * Initialize the HandlerAdapters used by this class.
	 * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
	 * we default to SimpleControllerHandlerAdapter.
	 */
	private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;

		if (this.detectAllHandlerAdapters) {
			// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
       //对于HandlerAdapter,服务器在启动的时候会先去查找我们在配置文件中配置的处理对象类,如果存在则使用(忽略spring默认配置的)
Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());// We keep HandlerAdapters in sorted order.OrderComparator.sort(this.handlerAdapters);}}else {try {HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);this.handlerAdapters = Collections.singletonList(ha);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerAdapter later.}}// Ensure we have at least some HandlerAdapters, by registering// default HandlerAdapters if no other adapters are found.if (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");}}}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值