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

    分析下springmvc的HandlerMapping映射的抽象类

    初始化操作

    通过initApplicationContext()方法进行初始化,其一般是由父类执行ApplicationContextAware#setApplicationContext()方法间接调用,源码奉上

    	protected void initApplicationContext() throws BeansException {
    		//供子类扩展添加拦截器,目前spring没有自行实现
    		extendInterceptors(this.interceptors);
    		//搜寻springmvc中的MappedInterceptors保存至adaptedInterceptors集合
    		detectMappedInterceptors(this.adaptedInterceptors);
    		//将interceptors集合添加至adaptedInterceptors集合中
    		initInterceptors();
    	}
    

    主要目的是获取springmvc上下文中的拦截器集合,此处特指MappedInterceptor

    AbstractHandlerMapping#getHandler()-获取处理链对象

    源码奉上

    	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    		//getHandlerInternal(request)方法为抽象方法,供子类实现
    		//获取到的handler对象一般为bean/HandlerMethod
    		Object handler = getHandlerInternal(request);
    		//上述找不到则使用默认的处理类,没有设定则返回null,则会返回前台404错误
    		if (handler == null) {
    			handler = getDefaultHandler();
    		}
    		if (handler == null) {
    			return null;
    		}
    		// Bean name or resolved handler?
    		if (handler instanceof String) {
    			String handlerName = (String) handler;
    			handler = getApplicationContext().getBean(handlerName);
    		}
    		//创建处理链对象
    		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    		//针对cros跨域请求的处理,此处就不分析了
    		if (CorsUtils.isCorsRequest(request)) {
    			CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
    			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
    			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
    			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    		}
    		return executionChain;
    	}
    

    由以上代码分析可知,需要观察下如何获取handler对象以及创建HandlerExecutionChain处理链对象

    AbstractHandlerMethodMapping#getHandlerInternal()-针对HandlerMethod的获取

    主要是解析@Controller注解类中的@RequestMapping方法得到其中的HandlerMethod对象作为返回的Handler

    	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    		//获取访问的路径,一般类似于request.getServletPath()返回不含contextPath的访问路径
    		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    		
    		//获取读锁
    		this.mappingRegistry.acquireReadLock();
    		try {
    			//获取HandlerMethod作为handler对象,这里涉及到路径匹配的优先级
    			//优先级:精确匹配>最长路径匹配>扩展名匹配
    			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
    			//HandlerMethod内部含有bean对象,其实指的是对应的Controller
    			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    		}
    		finally {
    			//释放读锁
    			this.mappingRegistry.releaseReadLock();
    		}
    	}
    

    AbstractUrlHandlerMapping#getHandlerInternal()-针对beanName的获取

    源码奉上,此处的逻辑就较为简单了

    	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    		//从handlerMap查找路径对应的beanName
    		Object handler = lookupHandler(lookupPath, request);
    		if (handler == null) {
    			// We need to care for the default handler directly, since we need to
    			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
    			Object rawHandler = null;
    			if ("/".equals(lookupPath)) {
    				rawHandler = getRootHandler();
    			}
    			if (rawHandler == null) {
    				rawHandler = getDefaultHandler();
    			}
    			if (rawHandler != null) {
    				// Bean name or resolved handler?
    				if (rawHandler instanceof String) {
    					String handlerName = (String) rawHandler;
    					rawHandler = getApplicationContext().getBean(handlerName);
    				}
    				validateHandler(rawHandler, request);
    				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
    			}
    		}
    		
    		return handler;
    	}
    

    AbstractHandlerMapping#getHandlerExecutionChain()-创建处理链对象

    先附上HandlerExecutionChain的内部属性

            //真实处理请求对象
    	private final Object handler;
            
            //拦截器集合
    	private HandlerInterceptor[] interceptors;
            
            //拦截器集合
    	private List<HandlerInterceptor> interceptorList;
            
            //拦截器开始下标,默认正序执行
    	private int interceptorIndex = -1;
    

    再奉上创建处理链对象的源码

    	//此处的handler可为HandlerMethod/beanName
    	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
    				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    
    		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
    			if (interceptor instanceof MappedInterceptor) {
    				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
    				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
    					chain.addInterceptor(mappedInterceptor.getInterceptor());
    				}
    			}
    			else {
    				chain.addInterceptor(interceptor);
    			}
    		}
    		return chain;
    	}
    

    处理链的创建基本就是 带有handler对象以及添加拦截器对象集合,用于后期的拦截

    • HandlerExecutionChain处理链内部含有handler对象,可为@RequestMapping对应的HandlerMethod对象,也可为springmvc上下文的beanName

    • HandlerExecutionChain处理链内部主要包含拦截器对象,其可从springmvc上下文获取HandlerInterceptor/MappedHandlerInterceptor类型作为内部集合;
      当然此处获得拦截器集合也是根据路径匹配获取的,比如mvc:interceptor指定的或者mvc:resource指定的

    小结

  • 相关阅读:
    一天时间用python写门语言
    360以安全之名做搜索,可信,还是欺世盗名?
    Servicemix,Karaf和Camel
    Struts2>action 小强斋
    解决JBoss只能通过localhost(127.0.0.1)而不能通过IP访问 小强斋
    java.sql.SQLException: 关闭的连接 小强斋
    Struts2>action 小强斋
    flex>MXML语法 小强斋
    jsp>tomcat配置虚拟目录 小强斋
    解决JBoss只能通过localhost(127.0.0.1)而不能通过IP访问 小强斋
  • 原文地址:https://www.cnblogs.com/question-sky/p/7126368.html
Copyright © 2011-2022 走看看