承接前文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只是对路径进行细心化的处理
对不以"/"开头的路径,加上"/"前缀
对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.
SimpleUrlHandlerMapping
和BeanNameUrlHandlerMapping
其基本都是对以/
开头的路径绑定以org.springframework.web.servlet.mvc.Controller
为接口实现类,前者间接关联,后者直接关联