SpringMVC系列(二)HandlerMapping初始化

SpringMVC源码解析一:HandlerMapping初始化 initHandlerMappings()方法初始化有两种方式: 1.setApplicationContext() 2.afterPropertiesSet() 1.setApplicationContext()实现方式如下: 首先进入DispatcherServlet 类中,可以看到DispatcherServlet 的继承关系: DispatcherServlet ex... 阅读详情

版权声明:本文为优快云博主「雨剑yyy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/csdn_20150804/article/details/103943435


基于springboot2.1.4;
springmvc执行,核心逻辑是在DispatchServlet中,其中的若干属性,初始值都是null,如下:

package org.springframework.web.servlet;

public class DispatcherServlet extends FrameworkServlet {
    ......
    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        //主要分析这个
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }
    ......
} 	

上篇文章中,DispatchServlet在执行相关逻辑时,都是直接使用了上边这些属性,本文分析下这些属性是何时在哪里被初始化的,并以handlerMappings为例,着重分析。

DispatchServlet类是个servlet,包含init方法,tomcat容器在启动时,会默认执行init方法,而DispatchServlet的父类HttpServletBean实现了Servlet接口的init方法。因此我们从HttpServletBean#init() 方法开始。

1.HttpServletBean#init()

package org.springframework.web.servlet;

public abstract class HttpServletBean extends HttpServlet implements 
                                        EnvironmentCapable, EnvironmentAware {
	......
    public final void init() throws ServletException {

        // Set bean properties from init parameters.
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        if (!pvs.isEmpty()) {
            try {
                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
                bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
                initBeanWrapper(bw);
                bw.setPropertyValues(pvs, true);
            }
            catch (BeansException ex) {
                if (logger.isErrorEnabled()) {
                    logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
                }
                throw ex;
            }
        }

        // Let subclasses do whatever initialization they like.
        //此方法是个空方法,目的是留给子类自己去实现一些初始化动作
        initServletBean();
    }
	......
}    

上面方法,其中关键方法是最后一行 initServletBean();这是个空方法,实现在其子类FrameworkServlet中实现,FrameworkServlet是DispatchServlet的直接父类。继续看下initServletBean的实现,

package org.springframework.web.servlet;

@SuppressWarnings("serial")
public abstract class FrameworkServlet extends HttpServletBean 
                                       implements ApplicationContextAware {
    ......
    protected final void initServletBean() throws ServletException {
        getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
        if (logger.isInfoEnabled()) {
            logger.info("Initializing Servlet '" + getServletName() + "'");
        }
        long startTime = System.currentTimeMillis();

        try {
            //初始化springmvc web容器
            this.webApplicationContext = initWebApplicationContext();
            //
            initFrameworkServlet();
        }
        catch (ServletException | RuntimeException ex) {
            logger.error("Context initialization failed", ex);
            throw ex;
        }

        if (logger.isDebugEnabled()) {
            String value = this.enableLoggingRequestDetails ?
                    "shown which may lead to unsafe logging of potentially sensitive data" :
                    "masked to prevent unsafe logging of potentially sensitive data";
            logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
                    "': request parameters and headers will be " + value);
        }

        if (logger.isInfoEnabled()) {
            logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
        }
    }
    ......   
}    

其中initWebApplicationContext()表示初始化web容器,进入,

package org.springframework.web.servlet;

@SuppressWarnings("serial")
public abstract class FrameworkServlet extends HttpServletBean 
                                       implements ApplicationContextAware {
    ......
    protected WebApplicationContext initWebApplicationContext() {
        //得到根容器,也就是springmvc的父容器,spring容器ApplicationContext
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;

        if (this.webApplicationContext != null) {
            // A context instance was injected at construction time -> use it
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent -> set
                        // the root application context (if any; may be null) as the parent
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            // No context instance was injected at construction time -> see if one
            // has been registered in the servlet context. If one exists, it is assumed
            // that the parent context (if any) has already been set and that the
            // user has performed any initialization such as setting the context id
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            // No context instance is defined for this servlet -> create a local one
            wac = createWebApplicationContext(rootContext);
        }

        if (!this.refreshEventReceived) {
            // Either the context is not a ConfigurableApplicationContext with refresh
            // support or the context injected at construction time had already been
            // refreshed -> trigger initial onRefresh manually here.
            //刷新容器
            synchronized (this.onRefreshMonitor) {
                onRefresh(wac);
            }
        }

        if (this.publishContext) {
            // Publish the context as a servlet context attribute.
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }

        return wac;
    }
    ......   
}      

从上面方法可以看出,web容器实际上是spring容器的子容器,web容器内部包含了父容器的引用,然后再包含自己特有的一些内容,这些内容在onRefresh(wac);方法中初始化,继续进入onRefresh方法,

2.DispatcherServlet#onRefresh(ApplicationContext context)

package org.springframework.web.servlet;

public class DispatcherServlet extends FrameworkServlet {
    ......
    protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}    
    
    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        //初始化HandlerMappings
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }
    ......
}    

这里使用了策略模式,其中initHandlerMappings(context);就是用来初始化handlerMappings属性的。

package org.springframework.web.servlet;

public class DispatcherServlet extends FrameworkServlet {
    ......
    private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {//默认是true,扫描所有
			// 从ApplicationContext中,找类型是HandlerMapping的bean
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				//初始化handlerMappings属性
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
		//如果容器中一个handlerMapping都没有,则给一个默认的,就是去DispatcherServlet.properties配置文件中读取
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}
	......
}

上述方法中,handlerMappings是从上下文容器中直接get出来的,如果get不到,会使用默认的配置:其实从上述方法中的log信息中可以看出,有个叫DispatcherServlet.properties的配置文件。
打开看下:

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

从配置文件中我们可以发现,所有初始化所需要的内容都在这里了,其中包括HandlerMapping,共有两个。

但是,如果容器中有,就不会使用默认的,那么容器中是何时放进去的呢,
我们就直接分析springboot中的初始化逻辑。

3.WebMvcAutoConfiguration初始化配置

我们知道springboot在启动的时候,默认会加载spring.factories文件中的配置类,在spring-boot-autoconfigure.jar包下的spring.factories文件中,有如下内容:
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,

就是这个WebMvcAutoConfiguration,初始化了所有webmvc的配置,在这里面可以找到此配置类中还有个EnableWebMvcConfiguration内部类,可以发现他继承了WebMvcConfigurationSupport,所有HandlerMappings都能在这俩配置类中找到(代码比较多,就不贴出来了)。

4.RequestMappingHandlerMapping初始化

这里看下一个比较重要的HandlerMapping,RequestMappingHandlerMapping 的初始化代码,RequestMappingHandlerMapping专门用来处理@Controller修饰的bean,这种方式也是我们开发中最常用的。

package org.springframework.web.servlet.config.annotation;

public class WebMvcConfigurationSupport implements ApplicationContextAware, 
                                                    ServletContextAware {
    @Bean
    @SuppressWarnings("deprecation")
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
        @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
        @Qualifier("mvcConversionService") FormattingConversionService conversionService,
        @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

        RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
        mapping.setOrder(0);
        mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
        mapping.setContentNegotiationManager(contentNegotiationManager);
        mapping.setCorsConfigurations(getCorsConfigurations());

        PathMatchConfigurer configurer = getPathMatchConfigurer();

        Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
        if (useSuffixPatternMatch != null) {
            mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
        }
        Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
        if (useRegisteredSuffixPatternMatch != null) {
            mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
        }
        Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
        if (useTrailingSlashMatch != null) {
            mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
        }

        UrlPathHelper pathHelper = configurer.getUrlPathHelper();
        if (pathHelper != null) {
            mapping.setUrlPathHelper(pathHelper);
        }
        PathMatcher pathMatcher = configurer.getPathMatcher();
        if (pathMatcher != null) {
            mapping.setPathMatcher(pathMatcher);
        }
        Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
        if (pathPrefixes != null) {
            mapping.setPathPrefixes(pathPrefixes);
        }

        return mapping;
    }

	protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
		return new RequestMappingHandlerMapping();
	}
}

上面这段代码,是告诉spring容器实例化一个RequestMappingHandlerMapping,并且设置了一些属性值。

而RequestMappingHandlerMapping类还实现了接口InitializingBean,所以在实例化后,会执行afterPropertiesSet()方法:

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
		implements MatchableHandlerMapping, EmbeddedValueResolverAware {
	......	
	public void afterPropertiesSet() {
		//初始化RequestMappingInfo的config
		this.config = new RequestMappingInfo.BuilderConfiguration();
		this.config.setUrlPathHelper(getUrlPathHelper());
		this.config.setPathMatcher(getPathMatcher());
		this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
		this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
		this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
		this.config.setContentNegotiationManager(getContentNegotiationManager());
		//调用父类方法
		super.afterPropertiesSet();
	}
	......

打开父类方法:

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping 
													implements InitializingBean {
	......													
	public void afterPropertiesSet() {
		initHandlerMethods();
	}
	
	protected void initHandlerMethods() {
		//从spring容器中拿到所有bean,然后遍历
		for (String beanName : getCandidateBeanNames()) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				//扫描所有handler方法,就是controller层的方法
				processCandidateBean(beanName);
			}
		}
		//记录个日志
		handlerMethodsInitialized(getHandlerMethods());
	}
	......
}	

上述方法中,spring拿到容器中的诉苦有bean,然后遍历处理,让我们看下如何处理的,

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping 
													implements InitializingBean {
	......	
	protected void processCandidateBean(String beanName) {
		Class<?> beanType = null;
		try {
			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);
			}
		}
		if (beanType != null && isHandler(beanType)) {
			//探测寻找Handler方法
			detectHandlerMethods(beanName);
		}
	}
	
	protected abstract boolean isHandler(Class<?> var1);
	......
}	

上述代码逻辑就是判断一个bean是不是Handler(就是所谓的controller),如果是,那么就继续扫描Handler中的方法,并注册;其中判断isHandler(beanType)用来判断是否是handler。
因为我们这里分析的是RequestMappingHandlerMapping,所以isHandler方法在此类中实现:

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
		implements MatchableHandlerMapping, EmbeddedValueResolverAware {
	......	
	protected boolean isHandler(Class<?> beanType) {
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
	}
	......
}

就是判断bean上是否有@Controller注解或者@RequestMapping注解。

下面继续看下spring如何探测handler方法然后如何注册的,

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping 
													implements InitializingBean {
	......
	protected void detectHandlerMethods(Object handler) {
	    //handler对象就是我们定义的一个Controller
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());
	
		if (handlerType != null) {
			Class<?> userType = ClassUtils.getUserClass(handlerType);
			//扫描到Controller中的所有方法,key是方法名,value是路径名
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
							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) -> {
				//如果有代理,这里要找到被代理后的方法
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				//注册Method
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}
	......
}

上述代码逻辑,首先拿到Controller中的所有方法以及方法上的路径,如果方法有被代理,要使用被代理后的方法;然后遍历进行注册;
下面看下注册的逻辑:

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping 
                                                   implements InitializingBean {
    private final AbstractHandlerMethodMapping<T>.MappingRegistry mappingRegistry = new AbstractHandlerMethodMapping.MappingRegistry();
    ......   
	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		this.mappingRegistry.register(mapping, handler, method);
	}
	...... 
}

其中,MappingRegistry是AbstractHandlerMethodMapping的内部类,里面维护了一堆map,

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping 
                                                   implements InitializingBean {
    ......                                               
	class MappingRegistry {
		private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
		private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
		private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
		private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
		private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
		private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
		......
	}
	......
}

注册就是往这些map中存东西:

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping 
                                                   implements InitializingBean {
    ......         
    class MappingRegistry {
    	......
		public void register(T mapping, Object handler, Method method) {
			this.readWriteLock.writeLock().lock();
			try {
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
				assertUniqueMethodMapping(handlerMethod, mapping);
				//存储请求路径(包括请求方式)和请求方法的映射关系
				this.mappingLookup.put(mapping, handlerMethod);
		
				List<String> directUrls = getDirectUrls(mapping);
				for (String url : directUrls) {
				//存储url和请RequestMapping注解中的信息映射
					this.urlLookup.add(url, mapping);
				}
		
				String name = null;
				if (getNamingStrategy() != null) {
					name = getNamingStrategy().getName(handlerMethod, mapping);
					addMappingName(name, handlerMethod);
				}
		
				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();
			}
		}
		......
	}	
}

说下参数:
mapping:是方法上的路径信息(@RequestMpping注解中的信息),包括请求方式GET/POST等;
handler:就是Controller对象;
method:Controller中的方法;
注册的过程就是MappingRegistry存请求路径处理方法等相关的映射关系,而这些东西最终会在DispatcherServlet处理前端请求时使用到,也就是上篇文章中,我们分析的内容。

本文先分析到这里,其他初始化内容也是和HandlerMapping一样的,具体代码就不再展示了,直接在配置类中搜索相关内容即可。

SpringMVC执行流程:详解HandlerMapping和HandlerAdapter 职责分离:将URL映射逻辑独立出来多种策略:支持注解、XML、Bean名称等多种映射方式启动时初始化:映射关系在应用启动时建立,提高运行时性能。 阅读详情

相关推荐

java技术专家 【必学基础框架】 3-SpringMVC源码-HandlerMapping

AbstractHandlerMapping是HandlerMapping的抽象实现,同时实现了Order接口继承了WebApplicationObjectSupport类,order接口主要是为了如果spring容器中有多个HandlerMapping,则按照order 排序去一次使用HandlerMapping获取handler对象,order小的优先被使用。

大壮 1170

Spring MVC与Web环境(三):HandlerMapping的配置以及处理请求

在上一篇的博客中,我提到了关于HandlerMapping的作用。在原书中作者是这样定义它的。每一个HandlerMapping可以持有一系列从URL请求到Controller的映射。在每一个HandlerMapping中都定义了一个map来持有这一系列的映射关系。在这个方法的定义中,通过解析request请求获取其中请求的URL路径,然后找到对应的handler对象,将这个对象封装到Handle...

SmilingCobra 749

不用API Key也能玩转Obsidian AI:本地大模型离线配置全攻略

本文详细介绍了如何在无需API Key的情况下,通过本地部署大型语言模型(LLM)为Obsidian注入AI能力。文章以Ollama为例,提供了从环境准备、模型选择到与Obsidian插件(如Text Generator)集成的完整配置攻略,旨在帮助用户打造一个安全、离线可用的智能笔记工作流,实现数据隐私与AI助力的完美结合。

weixin_29062963的博客 816

Spring MVC核心组件之HandlerMapping详解

当一个web请求到来时,DispatcherServlet负责接收请求并响应结果。DispatcherServlet首先需要找到当前请求对应的handler(处理器)来处理请求,流程如下图所示。DispatcherServlet中有一个成员变量叫做handlerMappings,是一个HandlerMapping的集合,当请求到来时,DispatcherServlet遍历handlerMappings中的每一个HandlerMapping以获取对应的handler。

老码农的博客 1808

如何读懂CiteSpace图谱?科研小白必看的节点颜色/年轮/聚类解读手册

本文详细解析CiteSpace图谱的核心视觉元素,包括节点颜色、年轮和聚类标识,帮助科研人员准确解读数据分析结果。通过生物医学案例展示如何从图谱中识别关键文献和研究趋势,提供五步系统解读法和常见错误规避策略,助力科研小白快速掌握文献计量分析技巧。

weixin_29179311的博客 310

Redis简介和项目应用

内存优先架构简介Redis的读写操作都是在内存中执行的,计算机内存的读写速度极快,比机械硬盘的读写快很多,因此也会比MySql采用机械读写的方式性能更高。但是这样会产生一个问题,当Redis重启之后,内存中的数据就会丢失,为了保证数据不会因为服务器重启而丢失,Redis实现了数据持久化的机制,这个机制会把数据存储到磁盘中,当服务器重启的时候,能够从磁盘中恢复原有的数据。

人工智能、机器学习 756

Spring MVC HandlerMapping : RequestMappingHandlerMapping 源代码解析

源代码版本 : spring-webmvc-5.1.4.RELEASE 概述 RequestMappingHandlerMapping是HandlerMapping的一个实现,主要用于针对控制器类(带有注解@Controller)中类级别或者方法级别的注解@RequestMapping创建RequestMappingInfo并管理。 RequestMappingHandlerMapping的实...

Details Inside Spring 2955

改善电流不匹配的级联电流镜布局设计 2002

模拟金属氧化物半导体 (MOS) 集成电路的性能在很大程度上取决于匹配精度的因素。 电流镜的匹配精度在模拟 IC 性能中尤为重要。 布局技术和器件尺寸被认为是可以在很大程度上改善匹配行为的主要因素。 尽管这些信息很重要,但对这两个因素的研究或研究有限。 在本文中,我们基于 Lan 等人 [1999] 提出的简单电流镜提出了一种新的级联电流镜布局技术。 Cascode电流镜的新布局在参数梯度存在的情况下改善了匹配特性。 讨论了跨晶体管有源区域的阈值梯度对电流镜匹配特性的影响。 使用 SPICE 仿真比较了新

Srfun的博客 4223

Spring MVC PathPatternMatchableHandlerMapping原理解析

在Spring MVC框架中,路由机制是实现HTTP请求到具体处理器方法映射的核心。是Spring 5之后引入的一个新特性,它基于来提供更为灵活和强大的URL路径匹配能力。与传统的相比,提供了更丰富的路径模式匹配特性,如参数化路径、正则表达式匹配等。

qq_32868023的博客 1390

用Java和MQTT搞定大疆无人机自动巡检:一个真实机场项目的踩坑与优化记录

本文详细介绍了如何利用Java和MQTT协议实现大疆无人机在机场自动巡检系统的开发与优化。通过实战案例分享系统架构设计、通信协议选型、断线重连机制及数据通道优化等关键环节,帮助开发者解决GPS信号漂移、MQTT消息风暴等典型问题,提升系统性能和可靠性。

weixin_30275415的博客 493

【技术科普】破解政务跨系统数据壁垒!亘川一网统管平台多源数据同步技术解析

本文解析亘川一网统管平台多源数据同步技术,针对政务跨系统数据壁垒难题,介绍组件的数据采集、校验、审计留痕等核心能力,结合营商环境项目落地案例,对比传统开发模式差异,讲解开源组件的实践价值,为政务项目开发者提供落地参考。

weixin_67440240的博客 634

SpringMVC之HandlerMapping

1.简介 在SpringMVC请求流程中我们可以看出,HandlerMapping是请求映射处理器,也就是通过请求的url找到对应的逻辑处理单元(Controller),注意这里只是建立请求与Controller的映射关系,最终的处理是通过HandlerAdapt来进行处理的。 2.初始化分析 在初识DispatcherServlet中提到过DispatcherServlet的初始化中会调用ini...

果子爸聊技术 5933

32、通用处理器通信平台发展与5G开源社区技术解析

本文探讨了基于通用处理器(GPP)的通信平台在5G技术中的发展现状与挑战,详细介绍了多个开源平台和硬件架构,并分析了软件加速方法和未来发展方向。文章指出,尽管GPP具有灵活性和开放性优势,但在实时信号处理和功耗等方面仍存在瓶颈,需要通过核心技术研发、标准化协作和应用拓展推动5G技术的实际应用。

orange的博客 128

【Spring MVC】HandlerMapping初始化详解(超详细过程源码分析)

Spring MVC的Control主要由HandlerMapping和HandlerAdapter两个组件提供。HandlerMapping负责映射用户的URL和对应的处理类,HandlerMapping并没有规定这个URL与应用的处理类如何映射,在HandlerMapping接口中只定义了根据一个URL必须返回一个由HandlerExecutionChain代表的处理链,我们可以在这个处理链中...

Yngz_Miao的博客 3万+

Ardupilot chibios IO固件,IO与FMU通信,固件下载(3)

目录 文章目录目录摘要 摘要 本节主要记录自己学习IO与FMU通信

陌城烟雨 2798

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

SpringMVC系列二:SpringMVC的HandlerMapping

将设置 url 到 ParameterizableViewController 的映射关系保存到 SimpleUrlHandlerMapping 中。将设置 url 到 ResourceHttpRequestHandler 的映射关系保存到 SimpleUrlHandlerMapping 中。最后拿到 viewName 之后进行视图渲染。请求处理的handleRequest方法。请求处理的handleRequest方法。直接将静态资源文件写到 socket 中。请求处理的handleRequest方法。

Running666的博客 501

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

SpringMVC系列:HandlerMapping初始化

https://blog.youkuaiyun.com/csdn_20150804/article/details/103943435 文章目录 1.HttpServletBean#init() 2.DispatcherServlet#onRefresh(ApplicationContext context) 3.WebMvcAutoConfiguration初始化配置 4.RequestMappingHandlerMapping初始化 基于s

yygr的博客 642

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

SpringMVC中HandlerMapping的初始化和一次请求的完整过程

Springmvc中HandlerMapping的初始化和一次请求的完调用过程HandlerMapping的初始化一个请求的过程 这里先放一张HandlerMapping的类图 HandlerMapping的初始化 关于HandlerMapping的使用,主要包括两个部分:注册和查找 ( HandlerMapping有多种实现 容器启动的时候有多个被注册会根据Order顺序加载或调用 此处以Re...

Mr_Oolong的博客 825

SpringMVC-HandlerMapping

HandlerMapping的作用根据request找到对应的处理器Handler,在HandlerMapping接口中有一个唯一的方法getHanler,HandlerMapping接口的定义如下:public interface HandlerMapping { HandlerExecutionChain getHandler(HttpServletRequest request) th

不瘦十斤不换名字 4790

Spring源码-Springmvc初始化handlerMapping

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、springmvc初始化handlerMapping时序图总结 前言 1、创建XmlWebApplicationContext 2、调用refresh()方法 3、bean都创建完成后发布上下文刷新事件,开始初始化handlerMapping 一、springmvc初始化handlerMapping时序图 总结 1、如果不配置handlerMapping实现类,那么会从DispatcherServlet.prope

常威打来福 378

HandlerMapping之RequestMappingHandlerMapping初始化

一、HandlerMapping类图 默认情况下,SpringMVC 将加载当前系统中所有实现了HandlerMapping 接口的bean。如果只期望SpringMVC加载指定的handlermapping 时,可以修改web.xml中的DispatcherServlet的初始参数,将detectAllHandlerMappings的值设置为false: <init-param>...

lemon 1163

SpringMVC 九大组件之 HandlerMapping 深入分析

前面跟小伙伴们分享了 SpringMVC 一个大致的初始化流程以及请求的大致处理流程,在请求处理过程中,涉及到九大组件,分别是: HandlerMapping HandlerAdapter HandlerExceptionResolver ViewResolver RequestToViewNameTranslator LocaleResolver ThemeResolver MultipartResolver FlashMapManager 这些组件相信小伙伴们在日常开发中多多少少都有涉及到,如果你对

江南一点雨的专栏 3045

《看透springMVC源码》笔记之HandlerMapping

springMVC的HandlerMapping解析

can_L的博客 1295

SpringMVC处理器映射器HandlerMapping

前言 在SpringMVC中会有很多请求,每个请求都需要一个Handler处理,具体接收到一个请求之后使用哪个Handler进行处理呢,他们的过程是什么。 HandlerMapping:负责映射用户的URL和对应的处理类Handler,HandlerMapping并没有规定这个URL与应用的处理类如何映射。所以在HandlerMapping接口中仅仅定义了根据一个URL必须返回一个由Handler...

clyu的博客 2687

Spring源码系列-第9章-SpringMVC请求处理源码和HandlerMapping原理

/HandlerMapping的registry中找映射,返回HandlerMethod,真正执行当前请求的方法 if(handler == null) {} //找到前面的目标方法以后,还要构造一个处理器链;= null) {}F7进入try {//寻找当前请求谁能处理 return(handlerMethod!= null?} }F7进入可以看到还是从mappingRegistry里获取。

youthlql的博客 1764
上一篇: Spring容器和IoC(控制反转)详解
下一篇: SpringMVC拦截器源码解析
sxudong2010
博客等级 码龄9年 27粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值