43、SpringBoot 源码分析 - SpringMVC源码之BeanNameUrlHandlerMapping处理器

BeanNameUrlHandlerMapping是什么

其实这个就是在用bean注解方法的时候填写的名字作为uri和bean处理器映射。先看例子,比如我定义了两种老的写法的处理器:
 
 
然后我在配置文件中注入他们,都命名了:
 
然后访问:
 
 
好像也挺方便哦,但是都要实现接口,而且方法参数是死的,无法做到直接获取需要的参数值,而ResourceHttpRequestHandler更强大,他可以任意传参数,只要能匹配的上都可以匹配,等于定制化,灵活,你可以实现任何你想要的参数类型,只要你编写解析器。我们来说说原理吧。

BeanNameUrlHandlerMapping初始化

他也是EnableWebMvcConfiguration创建的:
 

AbstractDetectingUrlHandlerMapping的detectHandlers

但是在ApplicationContextAwareProcessor的初始化之前的方法postProcessBeforeInitialization中,最后进行了处理器探测detectHandlers

protected void detectHandlers() throws BeansException {
   
     
		ApplicationContext applicationContext = obtainApplicationContext();
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
				applicationContext.getBeanNamesForType(Object.class));

		// 遍历所有容器里的beanName,找出beanName有uri的注册进去
		for (String beanName : beanNames) {
   
     
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
   
     
				// URL paths found: Let's consider it a handler.
				registerHandler(urls, beanName);
			}
		}

		if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
   
     
			logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
		}
	}

BeanNameUrlHandlerMapping的determineUrlsForHandler

名字或者别名以/开头的都放入url集合里。

@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);
	}

AbstractUrlHandlerMapping的registerHandler注册处理器

	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);
		}
	}

首先看不是懒初始化的单例且处理器只是个名字的话就直接实例化,然后判断重复,根据url的不同,设置不同的处理器,一般的就是放入url和处理器的映射集合。

	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;
			ApplicationContext applicationContext = obtainApplicationContext();
			if (applicationContext.isSingleton(handlerName)) {
   
     
				resolvedHandler = applicationContext.getBean(handlerName);
			}
		}

		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("/")) {
   
     
				if (logger.isTraceEnabled()) {
   
     
					logger.trace("Root mapping to " + getHandlerDescription(handler));
				}
				setRootHandler(resolvedHandler);
			}
			else if (urlPath.equals("/*")) {
   
     
				if (logger.isTraceEnabled()) {
   
     
					logger.trace("Default mapping to " + getHandlerDescription(handler));
				}
				setDefaultHandler(resolvedHandler);
			}
			else {
   
     
				this.handlerMap.put(urlPath, resolvedHandler);
				if (logger.isTraceEnabled()) {
   
     
					logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
				}
			}
		}
	}

处理原理

至于他的处理原理,还是获取处理器的方法lookupHandler,其实他和SimpleUrlHandlerMapping一样,都是AbstractDetectingUrlHandlerMapping的子类,所以实现是一样的,都是AbstractDetectingUrlHandlerMapping实现的,这个上几篇有讲过了,就不多说了。
 

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。