zoukankan      html  css  js  c++  java
  • SpringMVC源码情操陶冶-AbstractUrlHandlerMapping

    承接前文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只是对路径进行细心化的处理

    1. 对不以"/"开头的路径,加上"/"前缀

    2. 对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.SimpleUrlHandlerMappingBeanNameUrlHandlerMapping其基本都是对以/开头的路径绑定以org.springframework.web.servlet.mvc.Controller为接口实现类,前者间接关联,后者直接关联

  • 相关阅读:
    你是一直认为 count(1) 比 count(*) 效率高么?
    秒杀系统是如何防止超卖的?
    百亿流量微服务网关的设计与实现
    中台
    Token 、Cookie、Session
    HyperLedger Fabric 1.4 区块链应用场景(3.1)
    HyperLedger Fabric 1.4 区块链工作过程(2.3)
    HyperLedger Fabric 1.4 区块链技术原理(2.2)
    HyperLedger Fabric 1.4 区块链技术定义(2.1)
    HyperLedger Fabric 1.4 区块链技术发展(1.3)
  • 原文地址:https://www.cnblogs.com/question-sky/p/7132196.html
Copyright © 2011-2022 走看看