Spring中的HandlerMapping執(zhí)行流程詳解
HandlerMapping
HandlerMapping在Spring MVC框架的jar包下面,他是處理映射器,為用戶發(fā)送的請(qǐng)求找到合適的Handler Adapter,它將會(huì)把請(qǐng)求映射為HandlerExecutionChain對(duì)象(包含一個(gè)Handler處理器(頁(yè)面控制器)對(duì)象、多個(gè)HandlerInterceptor攔截器)對(duì)象,同時(shí)通過(guò)這種策略模式,很容易添加新的映射策略。
SpringMVC在請(qǐng)求到handler處理器的分發(fā)這步就是通過(guò)HandlerMapping模塊解決的,handlerMapping還處理攔截器,同時(shí)Spring MVC也提供了一系列HandlerMapping的實(shí)現(xiàn),根據(jù)一定的規(guī)則選擇controller。
public interface HandlerMapping {
// 返回請(qǐng)求的一個(gè)處理程序handler和攔截器interceptors
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}HandlerMapping執(zhí)行流程如下:
- 初始化流程:DispatcherServlet——>initHandlerMappings(context)
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//默認(rèn)為true,可通過(guò)DispatcherServlet的init-param參數(shù)進(jìn)行設(shè)置
if (this.detectAllHandlerMappings) {
//在ApplicationContext中找到所有的handlerMapping, 包括父級(jí)上下文
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
//排序,可通過(guò)指定order屬性進(jìn)行設(shè)置,order的值為int型,數(shù)越小優(yōu)先級(jí)越高
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
//從ApplicationContext中取id(或name)="handlerMapping"的bean,此時(shí)為空
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
// 將hm轉(zhuǎn)換成list,并賦值給屬性handlerMappings
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException ex) {
}
}
//如果沒(méi)有自定義則使用默認(rèn)的handlerMappings
//默認(rèn)的HandlerMapping在DispatcherServlet.properties屬性文件中定義,
// 該文件是在DispatcherServlet的static靜態(tài)代碼塊中加載的
// 默認(rèn)的是:BeanNameUrlHandlerMapping和RequestMappingHandlerMapping
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);//默認(rèn)策略
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}- 如果緩存中存在,則從緩存中獲取,并進(jìn)行排序
- 從ApplicationContext中取id(或name)="handlerMapping"的bean
- 如果沒(méi)有自定義則使用默認(rèn)的handlerMappings
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();//HandlerMappings
//獲取HandlerMappings為key的value值,defaultStrategies在static塊中讀取DispatcherServlet.properties
String value = defaultStrategies.getProperty(key);
if (value != null) {
//逗號(hào),分割成數(shù)組
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length);
for (String className : classNames) {
try {
//反射加載并存儲(chǔ)strategies
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
//通過(guò)容器創(chuàng)建bean 觸發(fā)后置處理器
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
。。。
}
return strategies;
}
else {
return new LinkedList<>();
}
}
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
//通過(guò)容器創(chuàng)建bean
return context.getAutowireCapableBeanFactory().createBean(clazz);
}獲取HandlerMappings為key的value值,defaultStrategies在static塊中讀取DispatcherServlet.properties
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\ org.springframework.web.servlet.function.support.RouterFunctionMapping
執(zhí)行service方法流程:DispatcherServlet——>doDispatch()——>getHandler(request)——>getHandlerExecutionChain(handler, request)——>new HandlerExecutionChain(handler))——>chain.addInterceptor(interceptor)
HandlerMapping是處理器映射器,根據(jù)請(qǐng)求找到處理器Handler,但并不是簡(jiǎn)單的返回處理器,而是將處理器和攔截器封裝,形成一個(gè)處理器執(zhí)行鏈(HandlerExecuteChain)。
AbstractHandlerMapping
獲取處理器執(zhí)行鏈的過(guò)程在AbstractHandlerMapping中的getHandler方法
- 先看看初始化過(guò)程
protected void initApplicationContext() throws BeansException {
//模板方法,用于給子類(lèi)提供一個(gè)添加Interceptors的入口。
extendInterceptors(this.interceptors);
//將SpringMvc容器和父容器中所有的MappedInterceptor類(lèi)型的Bean添加到mappedInterceptors的屬性
detectMappedInterceptors(this.mappedInterceptors);
//用于初始化Interceptor,將Interceptors屬性里所包含的對(duì)象按類(lèi)型添加到mappedInterceptors和adaptedInterceptors.
initInterceptors();
}AbstractHandlerMapping通過(guò)initApplicationContext()方法進(jìn)行自動(dòng)初始化,它的創(chuàng)建其實(shí)就是初始化上面三個(gè)interceptor,其一般是由父類(lèi)執(zhí)行ApplicationContextAware#setApplicationContext()方法間接調(diào)用,主要是獲取springmvc上下文中的攔截器集合MappedInterceptor。
- getHandler() 獲取處理鏈對(duì)象
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//getHandlerInternal(request)方法為抽象方法,供子類(lèi)實(shí)現(xiàn)
//獲取到的handler對(duì)象一般為bean/HandlerMethod
Object handler = getHandlerInternal(request);
//上述找不到則使用默認(rèn)的處理類(lèi),沒(méi)有設(shè)定則返回null,則會(huì)返回前臺(tái)404錯(cuò)誤
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);
}
//創(chuàng)建處理鏈對(duì)象
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//針對(duì)cros跨域請(qǐng)求的處理,此處就不分析了
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;
}
//針對(duì)HandlerMethod的獲取
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//獲取訪問(wèn)的路徑,一般類(lèi)似于request.getServletPath()返回不含contextPath的訪問(wèn)路徑
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//獲取讀鎖
this.mappingRegistry.acquireReadLock();
try {
//獲取HandlerMethod作為handler對(duì)象,這里涉及到路徑匹配的優(yōu)先級(jí)
//優(yōu)先級(jí):精確匹配>最長(zhǎng)路徑匹配>擴(kuò)展名匹配
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//HandlerMethod內(nèi)部含有bean對(duì)象,其實(shí)指的是對(duì)應(yīng)的Controller
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
//釋放讀鎖
this.mappingRegistry.releaseReadLock();
}
}
//針對(duì)beanName的獲取
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//從handlerMap查找路徑對(duì)應(yīng)的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;
}HandlerMapping是通過(guò)getHandler方法來(lái)獲取處理器Handler和攔截器Interceptors的,AbstractHandlerMapping實(shí)現(xiàn)獲取handler。
在獲取handler對(duì)象時(shí)是由其子類(lèi)實(shí)現(xiàn)的,分別為AbstractHandlerMethodMapping,AbstractUrlHandlerMapping
- AbstractHandlerMethodMapping當(dāng)bean被注入到容器后會(huì)執(zhí)行一系列的初始化過(guò)程,用于注解@Controller,@RequestMapping來(lái)定義controller。
//容器啟動(dòng)時(shí)會(huì)運(yùn)行此方法,完成handlerMethod的注冊(cè)操作
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}protected void initHandlerMethods() {
//獲取上下文中所有bean的name,不包含父容器
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
//日志記錄HandlerMethods的總數(shù)量
handlerMethodsInitialized(getHandlerMethods());
}protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
//根據(jù)name找出bean的類(lèi)型
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
//處理Controller和RequestMapping
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}//整個(gè)controller類(lèi)的解析過(guò)程
protected void detectHandlerMethods(Object handler) {
//根據(jù)name找出bean的類(lèi)型
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
//獲取真實(shí)的controller,如果是代理類(lèi)獲取父類(lèi)
Class<?> userType = ClassUtils.getUserClass(handlerType);
//對(duì)真實(shí)的controller所有的方法進(jìn)行解析和處理 key為方法對(duì)象,T為注解封裝后的對(duì)象RequestMappingInfo
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
// 調(diào)用子類(lèi)RequestMappingHandlerMapping的getMappingForMethod方法進(jìn)行處理,
// 即根據(jù)RequestMapping注解信息創(chuàng)建匹配條件RequestMappingInfo對(duì)象
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
//找出controller中可外部調(diào)用的方法
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
//注冊(cè)處理方法
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
后續(xù)主要是通過(guò)RequestMappingHandlerMapping 完成:- 通過(guò)方法isHandler(beanType)判斷是否處理Controller和RequestMapping
- 調(diào)用子類(lèi)RequestMappingHandlerMapping的getMappingForMethod方法進(jìn)行處理,即根據(jù)RequestMapping注解信息創(chuàng)建匹配條件RequestMappingInfo對(duì)象getMappingForMethod(method, userType);
- 注冊(cè)處理方法registerHandlerMethod(handler, invocableMethod, mapping)
- AbstractUrlHandlerMapping是AbstractHandlerMapping的子類(lèi),實(shí)現(xiàn)針對(duì)beanName注冊(cè)為handler對(duì)象。
//注冊(cè)u(píng)rl和Bean的map,將具體的Handler注入到url對(duì)應(yīng)的map中
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.
// 不是懶加載,默認(rèn)為false,即不是,通過(guò)配置SimpleUrlHandlerMapping屬性lazyInitHandlers的值進(jìn)行控制
// 如果不是懶加載并且handler為單例,即從上下文中查詢實(shí)例處理,此時(shí)resolvedHandler為handler實(shí)例對(duì)象;
// 如果是懶加載或者h(yuǎn)andler不是單例,即resolvedHandler為handler邏輯名
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
// 如果handler是單例,通過(guò)bean的scope控制
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));
}
//"/"-->設(shè)置為roothandler
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isTraceEnabled()) {
logger.trace("Default mapping to " + getHandlerDescription(handler));
}
//對(duì)"/*"的匹配設(shè)置默認(rèn)的handler
setDefaultHandler(resolvedHandler);
}
else {
//其余的路徑綁定關(guān)系則存入handlerMap
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isTraceEnabled()) {
logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}RequestMappingHandlerMapping
- 通過(guò)方法isHandler(beanType)判斷是否處理Controller和RequestMapping
@Override
protected boolean isHandler(Class<?> beanType) {
//獲取@Controller和@RequestMapping
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
public static boolean hasAnnotation(AnnotatedElement element, Class<? extends Annotation> annotationType) {
// Shortcut: directly present on the element, with no merging needed?
if (AnnotationFilter.PLAIN.matches(annotationType) ||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(element)) {
return element.isAnnotationPresent(annotationType);
}
// Exhaustive retrieval of merged annotations...
return findAnnotations(element).isPresent(annotationType);
}- requestMapping封裝成RequestMappingInfo對(duì)象
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//解析方法所在類(lèi)上的requestMapping
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);//合并類(lèi)和方法上的路徑,比如Controller類(lèi)上有@RequestMapping("/demo"),方法的@RequestMapping("/demo1"),結(jié)果為"/demo/demo1"
}
String prefix = getPathPrefix(handlerType);//合并前綴
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
//找到方法上的RequestMapping注解
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
//獲取自定義的類(lèi)型條件(自定義的RequestMapping注解)
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}- 注冊(cè)處理方法registerHandlerMethod(handler, invocableMethod, mapping)
public void register(T mapping, Object handler, Method method) {
// Assert that the handler method is not a suspending one.
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
}
this.readWriteLock.writeLock().lock();
try {
//beanName和method封裝成HandlerMethod對(duì)象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
//驗(yàn)證RequestMappingInfo是否有對(duì)應(yīng)不同的method,有則拋出異常
validateMethodMapping(handlerMethod, mapping);
//RequestMappingInfo和handlerMethod綁定
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);//可以配置多個(gè)url
for (String url : directUrls) {
//url和RequestMappingInfo綁定 可以根據(jù)url找到RequestMappingInfo,再找到handlerMethod
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);//方法名和Method綁定
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}BeanNameUrlHandlerMapping
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("index");
mav.addObject("message", "默認(rèn)的映射處理器示例");
return mav;
}<bean id="resourceView"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="/name.do" class="com.zy.mvc.controller.HelloController"></bean>//向上繼承自ApplicationObjectSupport實(shí)現(xiàn)ApplicationContextAware接口
public abstract class ApplicationObjectSupport implements ApplicationContextAware {
protected final Log logger = LogFactory.getLog(this.getClass());
@Nullable
private ApplicationContext applicationContext;
...
public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
if (context == null && !this.isContextRequired()) {
this.applicationContext = null;
this.messageSourceAccessor = null;
} else if (this.applicationContext == null) {
if (!this.requiredContextClass().isInstance(context)) {
throw new ApplicationContextException("Invalid application context: needs to be of type [" + this.requiredContextClass().getName() + "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
this.initApplicationContext(context);//模板方法,調(diào)子類(lèi)
} else if (this.applicationContext != context) {
throw new ApplicationContextException("Cannot reinitialize with different application context: current one is [" + this.applicationContext + "], passed-in one is [" + context + "]");
}
}
...
}
//AbstractDetectingUrlHandlerMapping
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();//加載攔截器
// 處理url和bean name,具體注冊(cè)調(diào)用父類(lèi)AbstractUrlHandlerMapping類(lèi)完成
detectHandlers();
}
//建立當(dāng)前ApplicationContext中controller和url的對(duì)應(yīng)關(guān)系
protected void detectHandlers() throws BeansException {
// 獲取應(yīng)用上下文
ApplicationContext applicationContext = obtainApplicationContext();
//獲取ApplicationContext中的所有bean的name(也是id,即@Controller的屬性值)
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext,Object.class) : applicationContext.getBeanNamesForType(Object.class));
//遍歷所有beanName
for (String beanName : beanNames) {
// 通過(guò)模板方法模式調(diào)用BeanNameUrlHandlerMapping子類(lèi)處理
String[] urls = determineUrlsForHandler(beanName);//判斷是否以/開(kāi)始
if (!ObjectUtils.isEmpty(urls)) {
//調(diào)用父類(lèi)AbstractUrlHandlerMapping將url與handler存入map
registerHandler(urls, beanName);
}
}
}
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);
}
}
//已存在且指向不同的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("/")) {
if (logger.isTraceEnabled()) {
logger.trace("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);//設(shè)置根處理器,即請(qǐng)求/的時(shí)候
}
else if (urlPath.equals("/*")) {
if (logger.isTraceEnabled()) {
logger.trace("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);//默認(rèn)處理器
}
else {
this.handlerMap.put(urlPath, resolvedHandler);//注冊(cè)進(jìn)map
if (logger.isTraceEnabled()) {
logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}處理器bean的id/name為一個(gè)url請(qǐng)求路徑,前面有"/"; 如果多個(gè)url映射同一個(gè)處理器bean,那么就需要定義多個(gè)bean,導(dǎo)致容器創(chuàng)建多個(gè)處理器實(shí)例,占用內(nèi)存空間; 處理器bean定義與url請(qǐng)求耦合在一起。
SimpleUrlHandlerMapping
間接實(shí)現(xiàn)了org.springframework.web.servlet.HandlerMapping接口,直接實(shí)現(xiàn)該接口的是org.springframework.web.servlet.handler.AbstractHandlerMapping抽象類(lèi),映射Url與請(qǐng)求handler bean。支持映射bean實(shí)例和映射bean名稱(chēng)
public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
// 存儲(chǔ)url和bean映射
private final Map<String, Object> urlMap = new LinkedHashMap<>();
// 注入property的name為mappings映射
public void setMappings(Properties mappings) {
CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
}
// 注入property的name為urlMap映射
public void setUrlMap(Map<String, ?> urlMap) {
this.urlMap.putAll(urlMap);
}
public Map<String, ?> getUrlMap() {
return this.urlMap;
}
// 實(shí)例化本類(lèi)實(shí)例入口
@Override
public void initApplicationContext() throws BeansException {
// 調(diào)用父類(lèi)AbstractHandlerMapping的initApplicationContext方法,只要完成攔截器的注冊(cè)
super.initApplicationContext();
// 處理url和bean name,具體注冊(cè)調(diào)用父類(lèi)完成
registerHandlers(this.urlMap);
}
// 注冊(cè)映射關(guān)系,及將property中的值解析到map對(duì)象中,key為url,value為bean id或name
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
} else {
urlMap.forEach((url, handler) -> {
// 增加以"/"開(kāi)頭
if (!url.startsWith("/")) {
url = "/" + url;
}
// 去除handler bean名稱(chēng)的空格
if (handler instanceof String) {
handler = ((String) handler).trim();
}
// 調(diào)用父類(lèi)AbstractUrlHandlerMapping完成映射
registerHandler(url, handler);
});
}
}
}SimpleUrlHandlerMapping類(lèi)主要接收用戶設(shè)定的url與handler的映射關(guān)系,其實(shí)際的工作都是交由其父類(lèi)來(lái)完成的
- AbstractHandlerMapping 在創(chuàng)建初始化SimpleUrlHandlerMapping類(lèi)時(shí),調(diào)用其父類(lèi)的initApplicationContext()方法,該方法完成攔截器的初始化
- AbstractUrlHandlerMapping在創(chuàng)建初始化SimpleUrlHandlerMapping類(lèi)時(shí),調(diào)用AbstractUrlHandlerMapping類(lèi)的registerHandler(urlPath,handler)方法
總結(jié)

到此這篇關(guān)于Spring中的HandlerMapping執(zhí)行流程詳解的文章就介紹到這了,更多相關(guān)HandlerMapping執(zhí)行流程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot項(xiàng)目刪除Bean或者不加載Bean的問(wèn)題解決
文章介紹了在Spring Boot項(xiàng)目中如何使用@ComponentScan注解和自定義過(guò)濾器實(shí)現(xiàn)不加載某些Bean的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-01-01
關(guān)于Java中的try-with-resources語(yǔ)句
這篇文章主要介紹了關(guān)于Java中的try-with-resources語(yǔ)句,try-with-resources是Java中的環(huán)繞語(yǔ)句之一,旨在減輕開(kāi)發(fā)人員釋放try塊中使用的資源的義務(wù),需要的朋友可以參考下2023-05-05
SpringMVC+MyBatis實(shí)現(xiàn)多數(shù)據(jù)源切換
在企業(yè)級(jí)應(yīng)用開(kāi)發(fā)中,經(jīng)常需要處理來(lái)自不同數(shù)據(jù)庫(kù)的數(shù)據(jù),為了滿足這一需求,我們可以通過(guò)配置多個(gè)數(shù)據(jù)源來(lái)實(shí)現(xiàn)對(duì)不同數(shù)據(jù)庫(kù)的訪問(wèn),下面我們來(lái)看看具體實(shí)現(xiàn)吧2025-01-01
SpringBoot中使用Quartz管理定時(shí)任務(wù)的方法
這篇文章主要介紹了SpringBoot中使用Quartz管理定時(shí)任務(wù)的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
如何解決SpringBoot定時(shí)任務(wù)報(bào)錯(cuò)Unexpected error occurred 
這篇文章主要介紹了如何解決SpringBoot定時(shí)任務(wù)報(bào)錯(cuò)Unexpected error occurred in scheduled task問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08

