標籤:ORC style rip sde file 邏輯 protect 這一 不同
先介紹一下:
BeanNameUrlHandlerMapping是基於設定檔的方式; 所有處理器需要在XML檔案中,以Bean的形式配置。
缺點:配置繁瑣; 如果多個URL對應同一個處理器,那麼需要配置多條,同時也會執行個體化多個對象等等。。。
因為springmvc 是基於spring的,所以他的初始化肯定是在spring容器初始化之後才進行的。
先上類圖:
可以看到BeanNameUrlHandlerMapping父類最終實現了ApplicationContextAware介面,所以Spring容器會自動注入ApplicationContext,方法為:
1 public final void setApplicationContext(ApplicationContext context) throws BeansException { 2 if (context == null && !this.isContextRequired()) { 3 this.applicationContext = null; 4 this.messageSourceAccessor = null; 5 } else if (this.applicationContext == null) { 6 if (!this.requiredContextClass().isInstance(context)) { 7 throw new ApplicationContextException("Invalid application context: needs to be of type [" + this.requiredContextClass().getName() + "]"); 8 } 9 10 this.applicationContext = context;11 this.messageSourceAccessor = new MessageSourceAccessor(context);12 this.initApplicationContext(context); //這塊實際上是一個鉤子方法,供子類去覆蓋! 進行初始化工作13 } else if (this.applicationContext != context) {14 throw new ApplicationContextException("Cannot reinitialize with different application context: current one is [" + this.applicationContext + "], passed-in one is [" + context + "]");15 }16 17 }
AbstractHandlerMapping: 這個類就是複寫了這個方法 進行了攔截器的初始化
protected void initApplicationContext() throws BeansException { this.extendInterceptors(this.interceptors); //供子類擴充攔截器 this.detectMappedInterceptors(this.mappedInterceptors);//掃描應用下的MappedInterceptor,並添加到mappedInterceptors this.initInterceptors();//歸集MappedInterceptor,並適配HandlerInterceptor和WebRequestInterceptor }
AbstractDetectingUrlHandlerMapping :同樣重寫這個方法,實現自己的邏輯
1 public void initApplicationContext() throws ApplicationContextException { 2 super.initApplicationContext(); 3 this.detectHandlers(); 4 } 5 6 protected void detectHandlers() throws BeansException { 7 if (this.logger.isDebugEnabled()) { 8 this.logger.debug("Looking for URL mappings in application context: " + this.getApplicationContext()); 9 }10 // 掃描應用下所有的Object類11 String[] beanNames = this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.getApplicationContext(), Object.class) : this.getApplicationContext().getBeanNamesForType(Object.class);12 String[] arr$ = beanNames;13 int len$ = beanNames.length;14 15 for(int i$ = 0; i$ < len$; ++i$) { //遍曆每一個掃描出來的類16 String beanName = arr$[i$];17 String[] urls = this.determineUrlsForHandler(beanName); //鉤子方法,讓子類去實現,通過handler解析url18 if (!ObjectUtils.isEmpty(urls)) {19 this.registerHandler(urls, beanName); //返回的URL進行註冊,實際上就是放到AbstractUrlHandlerMapping的一個map中20 } else if (this.logger.isDebugEnabled()) {21 this.logger.debug("Rejected bean name ‘" + beanName + "‘: no URL paths identified");22 }23 }24 25 }
BeanNameUrlHandlerMapping:實際上就實現了determineUrlsForHandler這個方法:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.springframework.web.servlet.handler;import java.util.ArrayList;import java.util.List;import org.springframework.util.StringUtils;public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping { public BeanNameUrlHandlerMapping() { } protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList(); if (beanName.startsWith("/")) { //只有一點需要注意 就是bean id 必須是以‘/‘開頭 urls.add(beanName); } String[] aliases = this.getApplicationContext().getAliases(beanName); String[] arr$ = aliases; int len$ = aliases.length; for(int i$ = 0; i$ < len$; ++i$) { String alias = arr$[i$]; if (alias.startsWith("/")) { urls.add(alias); } } return StringUtils.toStringArray(urls); }}
AbstractUrlHandlerMappin:中註冊處理器的方法:
1 protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { 2 Assert.notNull(urlPath, "URL path must not be null"); 3 Assert.notNull(handler, "Handler object must not be null"); 4 Object resolvedHandler = handler; 5 if (!this.lazyInitHandlers && handler instanceof String) { 6 String handlerName = (String)handler; 7 if (this.getApplicationContext().isSingleton(handlerName)) { 8 resolvedHandler = this.getApplicationContext().getBean(handlerName); 9 }10 }11 12 Object mappedHandler = this.handlerMap.get(urlPath);13 if (mappedHandler != null) {14 if (mappedHandler != resolvedHandler) { //不允許存在相同url不同handler,否則拋異常15 throw new IllegalStateException("Cannot map " + this.getHandlerDescription(handler) + " to URL path [" + urlPath + "]: There is already " + this.getHandlerDescription(mappedHandler) + " mapped.");16 }17 } else if (urlPath.equals("/")) {18 if (this.logger.isInfoEnabled()) {19 this.logger.info("Root mapping to " + this.getHandlerDescription(handler));20 }21 22 this.setRootHandler(resolvedHandler);23 } else if (urlPath.equals("/*")) {24 if (this.logger.isInfoEnabled()) {25 this.logger.info("Default mapping to " + this.getHandlerDescription(handler));26 }27 28 this.setDefaultHandler(resolvedHandler);29 } else { //這才是正常的儲存邏輯30 this.handlerMap.put(urlPath, resolvedHandler);31 if (this.logger.isInfoEnabled()) {32 this.logger.info("Mapped URL path [" + urlPath + "] onto " + this.getHandlerDescription(handler));33 }34 }35 36 }
到這裡實際上處理器映射器的儲存工作就算完事了。
實際上handlerMapping這一塊,主要思路就是 寫一個模板類,來處理公用的方法,如初始化攔截器,然後留下鉤子方法,讓子類去實現自己的邏輯就好了。
Spring MVC的handlermapping之BeanNameUrlHandlerMapping初始化