2023-09-14  阅读(2)
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105572361

BeanNameUrlHandlerMapping是什么

其实这个就是在用bean注解方法的时候填写的名字作为uri和bean处理器映射。先看例子,比如我定义了两种老的写法的处理器:

202309142304560911.png

202309142304571462.png
然后我在配置文件中注入他们,都命名了:

202309142304582003.png
然后访问:

202309142304592864.png

202309142304598795.png
好像也挺方便哦,但是都要实现接口,而且方法参数是死的,无法做到直接获取需要的参数值,而ResourceHttpRequestHandler更强大,他可以任意传参数,只要能匹配的上都可以匹配,等于定制化,灵活,你可以实现任何你想要的参数类型,只要你编写解析器。我们来说说原理吧。

BeanNameUrlHandlerMapping初始化

他也是EnableWebMvcConfiguration创建的:

202309142305011086.png

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实现的,这个上几篇有讲过了,就不多说了。

202309142305021247.png

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


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文