SpringMVC源码情操陶冶-AbstractUrlHandlerMapping

承接前文SpringMVC源码情操陶冶-AbstractHandlerMapping,前文主要讲解了如何获取handler处理对象,本文将针对beanName注册为handler对象作下解析

AbstractUrlHandlerMapping#registerHandler()-注册handler对象

内部含有两个此方法的重载,分别作简单的介绍

AbstractUrlHandlerMapping#registerHandler(String[] urlPaths, String beanName)-多路径绑定一个bean

多个路径绑定同一个bean,源码奉上

	protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
		Assert.notNull(urlPaths, "URL path array must not be null");
		//最终调用另外一个重载方法
		for (String urlPath : urlPaths) {
			registerHandler(urlPath, beanName);
		}
	}

AbstractUrlHandlerMapping#registerHandler(String urlPath,Object handler)-请求路径绑定bean

注意此处的urlPath参数可以为ant-style模式的值,源码奉上

	protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
		//两参数不可为空
		Assert.notNull(urlPath, "URL path must not be null");
		Assert.notNull(handler, "Handler object must not be null");
		Object resolvedHandler = handler;

		// Eagerly resolve handler if referencing singleton via name.
		if (!this.lazyInitHandlers && handler instanceof String) {
			String handlerName = (String) handler;
			if (getApplicationContext().isSingleton(handlerName)) {
				resolvedHandler = getApplicationContext().getBean(handlerName);
			}
		}
		
		//是否已存在对应的handler
		Object mappedHandler = this.handlerMap.get(urlPath);
		if (mappedHandler != null) {
			if (mappedHandler != resolvedHandler) {
				throw new IllegalStateException(
						"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
						"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
			}
		}
		else {
			//未存在
			if (urlPath.equals("/")) {
				//"/"-->设置为roothandler
				setRootHandler(resolvedHandler);
			}
			else if (urlPath.equals("/*")) {
				//对"/*"的匹配设置默认的handler
				setDefaultHandler(resolvedHandler);
			}
			else {
				//其余的路径绑定关系则存入handlerMap
				this.handlerMap.put(urlPath, resolvedHandler);
			
				}
			}
		}
	}

主要的目的只是将绑定关系通过handlerMap存储罢了,那么我们肯定想知道这个registerHandler方法是如何被调用的,且看下文

SimpleUrlHandlerMapping-直接实现类

简单的路径映射处理类,我们先看下其在springmvc中的使用

<bean id="simpleBean" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <pros>
            <pro key="/up">up</pro>
            <pro key="/down">down</pro>
            <pro key="/left">left</pro>
            <pro key="/right">right</pro>
        </pros>
    </property>
</bean>

<bean id="up" class="com.jing.springmvc.test.controller.UpController">

<bean id="down" class="com.jing.springmvc.test.controller.DownController">

<bean id="left" class="com.jing.springmvc.test.controller.LeftController">

<bean id="right" class="com.jing.springmvc.test.controller.RightController">

设置了上述属性后,实例后其会调用SimpleUrlHandlerMapping#setMappings()

	public void setMappings(Properties mappings) {
		CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
	}

在设置了上述的配置以后,SimpleUrlHandlerMapping则会调用AbstractHandlerMapping复写的方法initApplicationContext(),源码奉上

	@Override
	public void initApplicationContext() throws BeansException {
		//这在前文已知主要是获取interceptors
		super.initApplicationContext();
		//这里便是将上述的配置注册到AbstractUrlHandlerMapping#handlerMap中的入口
		registerHandlers(this.urlMap);
	}

转而看下上述的SimpleUrlHandlerMapping#registerHandlers(Map urlMap)方法

	protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
		//urlMap不可为空
		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();
				// Prepend with slash if not already present.
				if (!url.startsWith("/")) {
					url = "/" + url;
				}
				// Remove whitespace from handler bean name.
				if (handler instanceof String) {
					handler = ((String) handler).trim();
				}
				//调用父类的注册方法
				registerHandler(url, handler);
			}
		}
	}

由以上的代码可知,SimpleUrlHandlerMapping只是对路径进行细心化的处理

  1. 对不以"/"开头的路径,加上"/"前缀

  2. 对beanName进行去除空字符的处理,且beanName必须是springmvc上下文存在的,否则在绑定的过程中会抛异常

BeanNameUrlHandlerMapping例子

<beans ...>

   <bean
	class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

   <bean id="/welcome.htm"
        class="com.mkyong.common.controller.WelcomeController" />

   <bean id="/streetName.htm"
        class="com.mkyong.common.controller.StreetNameController" />

   <bean id="/process*.htm"
        class="com.mkyong.common.controller.ProcessController" />

</beans>

小结

1.AbstractUrlHandlerMapping主要是将请求路径绑定beanName,介绍了其直接实现类SimpleUrlHandlerMapping的注册步骤,比较简单,其余的实现类比如BeanNameUrlHandlerMapping会对以"/"开头的beanName注册,具体可自行去分析

2.SimpleUrlHandlerMappingBeanNameUrlHandlerMapping其基本都是对以/开头的路径绑定以org.springframework.web.servlet.mvc.Controller为接口实现类,前者间接关联,后者直接关联

原文地址:https://www.cnblogs.com/question-sky/p/7132196.html