這一次我們來看一下HandlerMapping的另一種實現(xiàn)方式BeanNameUrlHandlerMapping熄求。
配置文件
<bean name="/hello.htm" class="com.raistudies.ui.comtroller.HelloController"/>
<bean name="/sayHello*" class="com.raistudies.ui.comtroller.HelloController"/>
<bean id="urlHandler" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
好像完全看不出來"/hello.htm"和"/sayHello*"使用了BeanNameUrlHandlerMapping纪隙,因為它們之間直接都是分離的初橘,但為什么這樣可以調(diào)用BeanNameUrlHandlerMapping,我們看源碼來理解批什。
BeanNameUrlHandlerMapping類
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
/**
* Checks name and aliases of the given bean for URLs, starting with "/".
*/
@Override
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
}
BeanNameUrlHandlerMapping類中只有一個determineUrlsForHandler廊佩,這個方法很短膝宁,所做的功能就是找到beanName所對應(yīng)的urls,簡單點理解urls應(yīng)該就是本名+別名欧聘。
不過有個細節(jié)我們需要注意自沧,那就是BeanNameUrlHandlerMapping只會處理那些前綴為"/"的urls。
接下來看BeanNameUrlHandlerMapping的父類树瞭。
AbstractDetectingUrlHandlerMapping類
首先從initApplicationContext()看起
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}
里面調(diào)用了detectHandlers()
protected void detectHandlers() throws BeansException {
ApplicationContext applicationContext = obtainApplicationContext();
if (logger.isDebugEnabled()) {
logger.debug("Looking for URL mappings in application context: " + applicationContext);
}
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}
看到下面這行代碼
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
我們發(fā)現(xiàn)原來AbstractDetectingUrlHandlerMapping將配置文件中所有的bean都掃描了出來拇厢,因為Java中所有類都繼承Object。這也就解釋了最初的配置文件部分的疑問晒喷。
那么剩下的邏輯就很簡單了孝偎,就是將所有的以"/"開頭的url與其對應(yīng)handler進行綁定。
至于綁定邏輯和上一篇文章中所講的SimpleUrlHandlerMapping一樣了凉敲,因為它們都繼承了同一個父類AbstractUrlHandlerMapping衣盾。
總結(jié)
從源碼中我們可以理解BeanNameUrlHandlerMapping作為默認的HandlerMapping的原因寺旺,因為BeanNameUrlHandlerMapping掃描了配置文件中所有的bean。
注意事項:只有name開頭為"/"的bean才會被最終映射势决。