`
xifei321
  • 浏览: 20341 次
  • 性别: Icon_minigender_1
  • 来自: 无锡
文章分类
社区版块
存档分类
最新评论

SpringMVC DispatcherServlet的handlerMappings初始化

阅读更多


interface HandlerMapping 用来描述请求(request) 和 处理(handler)的映射(map)
主要方法:HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
根据请求返回一个HandlerExecutionChain 对象,该对象包含handler和对应的拦截器链,获取该对象后,在DispatcherServlet的doDispatch中先执行拦截器预处理,然后执行handler ,然后执行拦截器后处理,最后根据返回的ModelAndView 生成视图返回



一、DispatcherServlet实例化时执行静态块加载默认的初始化信息保存在defaultStrategies属性里
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized		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());
		}
	}


配置文件: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

.......
在DispatcherServlet的IOC容器中没有配置HandlerMapping bean时使用这个配置文件中配置的HandlerMapping。



====================================================================
二、在DispatcherServlet实例创建后,web容器会调用父类HttpServletBean的ini()方法,在该方法中调用initServletBean(),
由子类FrameworkServlet实现,完成DispatcherServlet的IOC容器创建和初始化
protected final void initServletBean() throws ServletException {
     ...
 //创建IOC容器,并初始化
    this.webApplicationContext = initWebApplicationContext();
     ...
}


protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext wac = findWebApplicationContext();
		if (wac == null) {
			// No fixed context defined for this servlet - create a local one.
			WebApplicationContext parent =
					WebApplicationContextUtils.getWebApplicationContext(getServletContext());
      //创建实例
	wac = createWebApplicationContext(parent);
		}

		if (!this.refreshEventReceived) {
          //由子类	DispatcherServlet实现						 onRefresh(wac);
		}

		.....

		return wac;
	}



在DispatcherServlet中重写了onRefresh
protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
	}



最终调用到initHandlerMappings(context)进行handlerMappings的初始化
private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
//是否需要一起找出parent中配置的HandlerMapping的bean
     if (this.detectAllHandlerMappings) {
//获取该容器以及所有parent容器中不重复的HandlerMapping类及其子类bean
  Map<String, HandlerMapping> matchingBeans =		BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
	if (!matchingBeans.isEmpty()) {
//如果配置了HandlerMapping类的bean,赋值给handlerMappings 
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
//排序实现了HandlerMapping接口,都要实现Ordered接口用来排序								OrderComparator.sort(this.handlerMappings);
			}
}
		else {
			try {
//从该容器中根据bean的名字,找出名为handlerMapping的bean
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.
			}
		}
		if (this.handlerMappings == null) {
//如果在容器中没获取到,根据读取配置文件defaultStrategies的信息,创建默认的HandlerMapping的list
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}






protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<T>(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(
							"Error loading DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]: problem with class file or dependent class", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<T>();
		}
	}





======================================================================
SimpleUrlHandlerMapping 实现:
首先在配置文件中定义
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="mappings">
               <props>
                   <prop key="login.do">LoginAction</prop>
               </props>
            </property>
</bean>

SimpleUrlHandlerMapping 类中有这2个方法:
  public void setMappings(Properties mappings) {
CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
	} 

public void setUrlMap(Map<String, ?> urlMap) {
		this.urlMap.putAll(urlMap);
	}


根据命名规则可以使用<property name="mappings">或<map name="urlMap">来配置映射。

SimpleUrlHandlerMapping 最上父类ApplicationObjectSupport 实现了ApplicationContextAware,当handlerMappings实例创建也就是调用getBean方法时,在AbstractAutowireCapableBeanFactory中
 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
       //创建bean实例
		if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
   .......
		Object exposedObject = bean;
		try {
  //根据容器中注册的bean定义设值属性
	populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
  //初始化方法调用
	exposedObject = initializeBean(beanName, exposedObject, mbd);
			}
   .......
		}
     


在initializeBean方法中调用了ApplicationContextAwareProcessor的postProcessBeforeInitialization方法,在这个方法中调用了该类的invokeAwareInterfaces(bean);
private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
//容器调用实现了ApplicationContextAware接口的方法
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}


在SimpleUrlHandlerMapping中重写了该方法
@Override
public void initApplicationContext() throws BeansException {
		super.initApplicationContext();
		registerHandlers(this.urlMap);
	}

protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
		if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
		}
		else {
			for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
	String url = entry.getKey();
	Object handler = entry.getValue();
								if (!url.startsWith("/")) {
			url = "/" + url;
				}
								if (handler instanceof String) {
		handler = ((String) handler).trim();
			}
//调用父类AbstractUrlHandlerMapping方法注册到该类的handlerMap中,在getHandler实现中使用这个map
	registerHandler(url, handler);
			}
		}
	}


AbstractUrlHandlerMapping中registerHandler方法:



分享到:
评论

相关推荐

    Spring框架系列(13) - SpringMVC实现原理之DispatcherServlet的初始化过程.doc

    SpringMVC DispatcherServlet 初始化过程详解 DispatcherServlet 是 SpringMVC 框架中的核心组件,对于 SpringMVC 的请求处理和响应起着至关重要的作用。DispatcherServlet 的初始化过程是 SpringMVC 实现原理的...

    SpringMVC源码剖析(三)- DispatcherServlet的初始化流程1

    在本文中,我们将深入探讨`DispatcherServlet`的初始化流程,这是SpringMVC的核心组件。`DispatcherServlet`扮演着中央调度者的角色,负责接收请求、解析请求信息,并调用合适的控制器进行业务逻辑处理。 首先,让...

    SpringMVC DispatcherServlet重写、自定义拦截器拦截器源码

    SpringMVC DispatcherServlet重写、自定义拦截器拦截器源码

    SpringMVC DispatcherServlet组件实现解析

    在 DispatcherServlet 的 init() 方法中,除了初始化 SpringIOC 容器外,还会初始化一些 SpringMVC 组件,包括: * MultipartResolver:处理multipart请求 * LocaleResolver:处理语言环境 * ThemeResolver:处理...

    Spring源码学习九:DispatcherServlet初始化源码分析1

    DispatcherServlet是SpringMVC的核心分发器,它实现了请求分发,是处理请求的入口,本篇将深入源码分析它的初始化过程。 首先,从DispatcherServlet的名称上可以看出它是一个Servlet,通过一张图来看一下它的实现...

    浅谈springmvc的DispatcherServlet分析

    同时,我们还指定了初始化参数contextConfigLocation,用于加载SpringMVC的配置文件spring-mvc.xml。 二、SpringMVC的配置文件 在SpringMVC的配置文件spring-mvc.xml中,我们需要配置controller的扫描路径和视图...

    Spring MVC启动时初始化的几个常用方法

    1. **加载配置**:`DispatcherServlet`会在初始化阶段读取配置文件(如`servlet-context.xml`),通过`WebApplicationContext`加载Bean定义。这个过程中,你可以自定义拦截器、视图解析器、异常处理器等关键组件。 ...

    从源码的角度来看SpringMVC.pdf

    DispatcherServlet的初始化流程涉及多个步骤,通过org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext 方法初始化WebApplicationContext,然后调用onRefresh方法进行refresh操作。...

    SpringMVC 处置流程分析

    总结,SpringMVC的处置流程始于Web应用的初始化,包括ContextLoaderListener加载根上下文和DispatcherServlet初始化子上下文。接着,DispatcherServlet负责接收和分发请求,通过HandlerMapping找到处理器,...

    SpringMVC URL 与 Controller 方法 初始化 源码赏析.vsdx

    SpringMVC URL 与 Controller 方法初始化源码流程 Visio 文档 文档可以直接通过Visio进行编辑,方便二次修改、学习

    welcome-file-list 与SpringMvc 的 DispatcherServlet

    在SpringMVC中 所有的请求都由dispatcherServlet处理(url-pattern配置的是/),当配置文件中有对静态资源的处理  时候 ,先匹配 welcome-file-list 中的文件,依次查找,找到了就 返回,如果没有找到就继续匹配到...

    SpringMVC 初始化 URL 与 Controller 方法 流程源码.vsdx

    SpringMVC URL 与 Controller 方法初始化源码流程 Visio 文档 文档可以直接通过Visio进行编辑,方便二次修改、学习

    Spring和SpringMVC父子容器关系

    SpringMVC中的DispatcherServlet在初始化时,会创建一个属于自己的ApplicationContext,我们通常称之为子容器。这个子容器负责处理与SpringMVC相关的bean,如Controller、ViewResolver、HandlerMapping等。...

    03springmvc注解驱动开发的servlet3.0初始化配置类.avi

    03springmvc注解驱动开发的servlet3.0初始化配置类.avi

    springMVC练手代码

    在`hou_job_springmvc2`或`hou_spring_mvc2`项目中,你可能会找到对应的配置文件(如`web.xml`),里面会定义DispatcherServlet的初始化参数。 2. **配置文件**:SpringMVC的配置通常在XML文件(如`servlet-context...

    SpringMVC+Hibernate+Spring整合实例

    首先,Spring会初始化并管理所有组件,包括SpringMVC的DispatcherServlet、Controller以及Hibernate的SessionFactory。然后,当用户发起HTTP请求时,DispatcherServlet捕获请求并转发给相应的Controller。Controller...

    SpringMVC入门案例源码

    这些文件定义了DispatcherServlet的初始化参数,控制器的映射,视图解析器等。 3. **@Controller注解**:标记在类上,表示该类为SpringMVC的控制器,处理来自客户端的请求。控制器中的方法通过@RequestMapping注解...

    SpringMVC入门最简洁工程

    `web.xml`是应用的部署描述符,用于配置前端控制器DispatcherServlet和SpringMVC的初始化参数。`spring-servlet.xml`是SpringMVC的核心配置文件,用于定义处理器映射器、视图解析器以及其他Bean。 **3. 最少的Jar包...

Global site tag (gtag.js) - Google Analytics