spring mvc请求映射关系处理

Spring MVC 初始化流程解析
本文详细解析了Spring MVC框架初始化过程中的关键步骤,包括DispatcherServlet的初始化策略、DefaultAnnotationHandlerMapping类层次关系及其工作原理等。通过跟踪核心类的执行流程,揭示了请求与处理器映射的关键机制。

1:看DispatcherServlet的初始化策略

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
//初始化处理器映射关系,即用户请求与程序处理的对应关系
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
	}

//initHandlerMappings默认会先探测ApplicationContext对象中已经设定好的任何HandlerMapping对象,如果有就使用定义好的,如果没有,调用方法getDefaultStrategies,使用默认配置,DisptatchServlet.properties文件中默认的org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping两个HandlerMapping对象。

 


2:看下DefaultAnnotationHandlerMapping类层次关系,BeanNameUrlHandlerMapping类层次是一样的

 

 

//类层次,凑合看
DefaultAnnotationHandlerMapping
	AbstractDetectingUrlHandlerMapping
		AbstractUrlHandlerMapping
			AbstractHandlerMapping
				extends WebApplicationObjectSupport implements HandlerMapping, Ordered

//这里继承了WebApplicationObjectSupport对象,关于这个对象:Convenient superclass for application objects running in a WebApplicationContext.
WebApplicationObjectSupport
	extends ApplicationObjectSupport implements ServletContextAware
		implements ApplicationContextAware



3:抽象类ApplicationObjectSupport实现了ApplicationContextAware,spring容器的后置处理器会调用setApplicationContext方法,执行顺序:

 

//ApplicationObjectSupport中的setApplicationContext方法执行
public final void setApplicationContext(ApplicationContext context) throws BeansException {
		if (context == null && !isContextRequired()) {
			// Reset internal context state.
			this.applicationContext = null;
			this.messageSourceAccessor = null;
		}
		else if (this.applicationContext == null) {
			// Initialize with passed-in context.
			if (!requiredContextClass().isInstance(context)) {
				throw new ApplicationContextException(
						"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
			}
			this.applicationContext = context;
			this.messageSourceAccessor = new MessageSourceAccessor(context);
//这里会先执行子类WebApplicationObjectSupport的initApplicationContext方法,然后到ApplicationObjectSupport自己的init方法,ApplicationObjectSupport本身的该方法没有任何处理,只是调用了一个空的方法initApplicationContext(),这个无参的重载方法被当作一个钩子供子类方法来实现。
			initApplicationContext(context);
		}
		else {
			// Ignore reinitialization if same context passed in.
			if (this.applicationContext != context) {
				throw new ApplicationContextException(
						"Cannot reinitialize with different application context: current one is [" +
						this.applicationContext + "], passed-in one is [" + context + "]");
			}
		}
	}



4:initApplicationContext()执行,spring默认的两个处理器映射类都继承自AbstractDetectingUrlHandlerMapping抽象类,而且类初始化将被执行的initApplicationContext方法也在这个类得到了实现

 

//AbstractDetectingUrlHandlerMapping中的initApplicationContext方法
public void initApplicationContext() throws ApplicationContextException {
//先执行超类的initApplicationContext方法,这个超类的方法完成的任务就是对定义好的拦截器改装并放入到adaptedInterceptors数组中供以后使用
		super.initApplicationContext();
//请求与处理器映射的关键方法
		detectHandlers();
	}



5:detectHandlers()执行

 

protected void detectHandlers() throws BeansException {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
		}
//默认会取得上下文中的所有的对象的beanname。
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		// Take any bean name that we can determine URLs for.
		for (int i = 0; i < beanNames.length; i++) {
			String beanName = beanNames[i];
//abstract方法,在子类中实现,即找到符合要求的映射url
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				// URL paths found: Let's consider it a handler.
//注册处理器,即添加一些映射关系到handlerMap中,一个LinkedHashMap
				registerHandler(urls, beanName);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Rejected bean name '" + beanNames[i] + "': no URL paths identified");
				}
			}
		}
	}



6:determineUrlsForHandler方法执行,DefaultAnnotationHandlerMapping为例子

 

不贴了,主要就是挨个对象查看,DefaultAnnotationHandlerMapping类就是查看定义的RequestMapping注解,然后把符合要求的urls返回。

转载于:https://my.oschina.net/dreamnight/blog/695069

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值