SpringMVC源码:HandlerMapping加载1
参考资料:
《SpringMVC源码解析系列》
《SpringMVC源码分析》
《Spring MVC源码》
写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。
前文:
《SpringMVC源码:DispatcherServlet初始化流程》
在前文中我们介绍了DispatcherServlet的初始化,其中有两个重要的过程分别是initHandlerMappings和initHandlerAdapters,本文我们介绍下这两个组件。
目录
一、HandlerMapping
1、HandlerMapping接口
2、AbstractHandlerMapping类
2.1、类属性
2.2、类方法
二、AbstractUrlHandlerMapping类
简介
类方法
registerHandler
getHandlerInternal
lookupHandler
buildPathExposingHandler
实现类
SimpleUrlHandlerMapping类
initApplicationContext
registerHandler
AbstractDetectingUrlHandlerMapping类
detectHandlers
BeanNameUrlHandlerMapping#determineUrlsForHandler
一、HandlerMapping
1、HandlerMapping接口
HandlerMapping接口定义主要用来提供request 请求对象和Handler对象 映射关系的接口。所谓request对象比如我们web应用中的http 请求,Handler对象则指的是对应rquest请求的相关处理逻辑(可以理解为我们对应改请求的业务处理逻辑)。
该接口只有一个方法getHandler(),入参是Http对应的请求对象,返回会值是HandlerExecutionChain对象,该对象包含一个处理器对象Handler和匹配该处理器的若干interceptors 拦截器列表。
public interface HandlerMapping {String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;}
下图是HandlerMapping接口以及其目前所有子类的UML类图:
从类图中可以看到HandlerMapping有一个初始的抽象类AbstractHandlerMapping,在该抽象类,分成两个体系一个是以AbstractUrlHandlerMapping(url和类级别的Handler处理器映射 url ->Controller),另一个是AbstractHandlerMethodMapping(url和method方法级别的Handler处理器)。
2、AbstractHandlerMapping类
AbstractHandlerMapping是HandlerMapping的抽象实现,同时实现了Order接口继承了WebApplicationObjectSupport类,order接口主要是为了如果spring容器中有多个HandlerMapping,则按照order 排序去一次使用HandlerMapping获取handler对象,order小的优先被使用。
由于该处理器抽象类继承WebApplicationObjectSupport对象,通过查看WebApplicationObjectSupport的继承关系,其也间接实现了ApplicationContextAware和ServlerContextAware,意味着该类在spring容器中被初始化完成后自动拥有ApplicationContext对象和ServletContext对象。
//WebApplicationObjectSupport.java@Overridepublic final void setServletContext(ServletContext servletContext) {if (servletContext != this.servletContext) {this.servletContext = servletContext;if (servletContext != null) {initServletContext(servletContext);}}}@Overrideprotected void initApplicationContext(ApplicationContext context) {super.initApplicationContext(context);if (this.servletContext == null && context instanceof WebApplicationContext) {this.servletContext = ((WebApplicationContext) context).getServletContext();if (this.servletContext != null) {initServletContext(this.servletContext);}}}
2.1、类属性
AbstractHandlerMapping包含以下类属性:
//如果处理器映射器没有获取到对应的Handlerm,则使用的默认Handler, 可以通过xml/注解的形式配置。private Object defaultHandler;//Url路径匹配的帮助类,包含ur编码方式设置获取,或者根据请求请求路径等方法private UrlPathHelper urlPathHelper = new UrlPathHelper();//Spring提供的路径匹配策略接口的路径匹配器private PathMatcher pathMatcher = new AntPathMatcher();//通过该属性来设置相关的拦截器,设置的方式可以通过xml配置private final List<Object> interceptors = new ArrayList<Object>();//该集合下的拦截器不需要匹配会通过getHandler()方法全部添加到HandlerExecutionChain中private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();//排序属性 默认最大值,如果不设置意味着其对应的处理器对象优先级最小private int order = Ordered.LOWEST_PRECEDENCE;
2.2、类方法
initApplicationContext()方法:对拦截器集合做处理
@Overrideprotected void initApplicationContext() throws BeansException {//spring提供钩子函数,子类可以实现该方法来为集合设置拦截器extendInterceptors(this.interceptors);//从spring容器中获取所有MappedInterceptordetectMappedInterceptors(this.adaptedInterceptors);//将所有设置在interceptors中的拦截器添加到adaptedInterceptors中initInterceptors();}//从spring容器中获取所有MappedInterceptor并添加到adaptedInterceptors中protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(getApplicationContext(), MappedInterceptor.class, true, false).values());}//将所有设置在interceptors中的拦截器添加到adaptedInterceptors中protected void initInterceptors() {if (!this.interceptors.isEmpty()) {for (int i = 0; i < this.interceptors.size(); i++) {Object interceptor = this.interceptors.get(i);if (interceptor == null) {throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");}this.adaptedInterceptors.add(adaptInterceptor(interceptor));}}}protected HandlerInterceptor adaptInterceptor(Object interceptor) {if (interceptor instanceof HandlerInterceptor) {return (HandlerInterceptor) interceptor;}else if (interceptor instanceof WebRequestInterceptor) {return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);}else {throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());}}
getHandler()方法:核心方法,主要作用是根据请求获取包装了Handler对象和拦截器的HandlerExecutionChain对象。该方法采用模板方法获取拦截器处理器链。
@Overridepublic final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//交由子类实现的根据请求获取处理器的具体逻辑 不同的子类获取Handler的逻辑不同Object handler = getHandlerInternal(request);//如果没有获取到Handler 则获取默认的Handler//默认的处理器可以通过配置映射器实例的时候通过属性设置if (handler == null) {handler = getDefaultHandler();}//如果默认的Handler还是没有则返回空if (handler == null) {return null;}//Handler处理器是字符串类型 说明获取的Handler是beanName//则从spring 容器中获取bean实例对象if (handler instanceof String) {String handlerName = (String) handler;handler = getApplicationContext().getBean(handlerName);}//为Handler添加拦截器,并最终返回HandlerExecutionChain对象HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);if (CorsUtils.isCorsRequest(request)) {CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain;}
getHandlerExecutionChain():将getHandlerInternal()方法返回的Handler对象包装成HandlerExecutionChain对象。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {//判断如果当前的Handler本身是HandlerExecutionChain对象 则强转//否则创建HandlerExecutionChain对象HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));//根据request找寻对应的逻辑处理路径 lookupPathString lookupPath = this.urlPathHelper.getLookupPathForRequest(request);//遍历所有拦截器for (HandlerInterceptor interceptor : this.adaptedInterceptors) {//判断是否为MappedInterceptor类型if (interceptor instanceof MappedInterceptor) {MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;//判断该拦截器是否与当前请求地址适配if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {//将拦截器加入到当前请求的执行链中chain.addInterceptor(mappedInterceptor.getInterceptor());}}else {chain.addInterceptor(interceptor);}}return chain;}
二、AbstractUrlHandlerMapping类
简介
AbstractUrlHandlerMapping继承自AbstractHandlerMapping类,从名字可以看出该类是一个urlPath和Handler对象对一一对应的HandlerMapping。
换句话说一个rquest可以解析出一个对应的路径urlPath 则一个路径可能会匹配最符合的一个与之对应的Handler对象,所以其有一个存储url和Handler对象对应关系的Map集合属性handlerMap。其还有两个属性一个是与url “/”对应的特定Handler对象,以及是否Handler 懒加载 lazyInitHandlers。
AbstractUrlHandlerMapping类有如下属性:
// /与"/" 匹配的特定RootHandler 用户可以在配置AbstractUrlHandlerMapping实例进行设置private Object rootHandler;// 是否懒加载Handler 如果是true 则map中可以存储string,在使用的时候才从spring容器中进行加载private boolean lazyInitHandlers = false;// 用于存储url和handler匹配的map集合private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
类方法
registerHandler
对urlpath 和Handler进行处理存放。
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);}}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;//lazyInitHandlers 为false 则不允许懒加载 对于Handler是string类型 需要从容器中获取到Handler实例存放到Map中//如果允许懒加载则 不需要进行实力获取 直接存储在使用的时候再从spring容器中获取if (!this.lazyInitHandlers && handler instanceof String) {String handlerName = (String) handler;if (getApplicationContext().isSingleton(handlerName)) {resolvedHandler = getApplicationContext().getBean(handlerName);}}//判断集合中对应的urlPath已存在且对应的Handler和要存储的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 {//集合中对应的urlPath不存在//对于 / 和/*进行特殊处理 / 讲Handler 存储在rootHandler中 /* 设置为defaultHandlerif (urlPath.equals("/")) { if (logger.isInfoEnabled()) {logger.info("Root mapping to " + getHandlerDescription(handler));}setRootHandler(resolvedHandler);}else if (urlPath.equals("/*")) {if (logger.isInfoEnabled()) {logger.info("Default mapping to " + getHandlerDescription(handler));}setDefaultHandler(resolvedHandler);}else {//非特殊情况则存放进map中this.handlerMap.put(urlPath, resolvedHandler);if (logger.isInfoEnabled()) {logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));}}}}
getHandlerInternal
整个请求分为两部分,首先根据请求路径获取到对应的Handler,然后对于获取到的Handler进行包装构造。在该方法中核心的两个方式是lookupHandler方法和buildPathExposingHandler方法
@Overrideprotected Object getHandlerInternal(HttpServletRequest request) throws Exception {//通过UrlPathHelper对象从request解析出urlPathString lookupPath = getUrlPathHelper().getLookupPathForRequest(request);//使用lookupPath 从HandlerMap中获取handler (精确匹配和Pattern匹配)Object handler = lookupHandler(lookupPath, request);//如果没有获取到 则可能是特殊路径或者该路径没有可以匹配的Handlerif (handler == null) {//如果没有获取到 则可能是特殊路径 需要特殊处理 比如 /路径匹配RootHandlerObject rawHandler = null;if ("/".equals(lookupPath)) {rawHandler = getRootHandler();}//没有匹配的Handler 则使用默认的handlerif (rawHandler == null) {rawHandler = getDefaultHandler();}//因为有可能有懒加载,需要对string类型的handler获取其实例if (rawHandler != null) {if (rawHandler instanceof String) {String handlerName = (String) rawHandler;rawHandler = getApplicationContext().getBean(handlerName);}//子类扩展 用于校验获取到的Handler是否匹配业务逻辑validateHandler(rawHandler, request);//返回添加了拦截器的HandlerExecutionChainhandler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);}}if (handler != null && logger.isDebugEnabled()) {logger.debug("Mapping [" + lookupPath + "] to " + handler);}else if (handler == null && logger.isTraceEnabled()) {logger.trace("No handler mapping found for [" + lookupPath + "]");}return handler;}
lookupHandler
该方法实现根据urlPath获取Handler。此时有两种情况 ,一是精确匹配,二是Pattern模式匹配,该方法中对这两种方式进行相关处理,其中Pattern模式匹配比较复杂,首先该方式可能会匹配到多个Handler,这里需要进行排序获取最优,同时针对最优有多个的情况进行处理,该方法中多次使用PathMatcher对象。
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {//先尝试从已有的映射关系中获取Object handler = this.handlerMap.get(urlPath);if (handler != null) {//获取Handler实例并构造HandlerExecuteChain对象返回if (handler instanceof String) {String handlerName = (String) handler;handler = getApplicationContext().getBean(handlerName);}validateHandler(handler, request);return buildPathExposingHandler(handler, urlPath, urlPath, null);}//handler 支持Pattern匹配 比如 /manager/student/* 类似的Pattern//该方式下无法直接获取而且 需要使用一种匹配方法 一个pathern可能匹配多个url 则需要获取其最优的HandlerList<String> matchingPatterns = new ArrayList<String>();//遍历handlerMap 获取所有PathMatcher匹配成功的Handler存放集合中for (String registeredPattern : this.handlerMap.keySet()) {if (getPathMatcher().match(registeredPattern, urlPath)) {matchingPatterns.add(registeredPattern);}else if (useTrailingSlashMatch()) {if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {matchingPatterns.add(registeredPattern + "/");}}}//根据PathMatcher获取到的排序器 对matchingPatterns 进行匹配 获取最优的Handler对象String bestMatch = null;Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);if (!matchingPatterns.isEmpty()) {Collections.sort(matchingPatterns, patternComparator);if (logger.isDebugEnabled()) {logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);}bestMatch = matchingPatterns.get(0);}//如果有最优Handler 则获取Handler实例对象if (bestMatch != null) {handler = this.handlerMap.get(bestMatch);if (handler == null) {if (bestMatch.endsWith("/")) {handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));}if (handler == null) {throw new IllegalStateException("Could not find handler for best pattern match [" + bestMatch + "]");}}if (handler instanceof String) {String handlerName = (String) handler;handler = getApplicationContext().getBean(handlerName);}validateHandler(handler, request);String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);//对于可能会有多个最优解的情况此处将所有的最优 即多个最优排序一样只是集合添加使其有先后Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();for (String matchingPattern : matchingPatterns) {if (patternComparator.compare(bestMatch, matchingPattern) == 0) {Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);uriTemplateVariables.putAll(decodedVars);}}if (logger.isDebugEnabled()) {logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);}return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);}// No handler found...return null;}
buildPathExposingHandler
为执行链增加两个拦截器PathExposingHandlerInterceptor与UriTemplateVariablesHandlerInterceptor。
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,String pathWithinMapping, Map<String, String> uriTemplateVariables) {HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));if (!CollectionUtils.isEmpty(uriTemplateVariables)) {chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));}return chain;}
实现类
从UML类图中可以大概清楚,在其抽象类下有两个分支,SimpleUrlHandlerMapping、AbstractDetectingUrlHandlerMappin,同时该类下还有一个子类BeanNameUrlHandlerMapping。在前文中我们介绍了AbstractUrlHandlerMapping类通过模板的方式实现了从请求request到Handler对象的主要逻辑,那么可想而知其后面的子类主要的功能点是初始化url和Handler的映射关系。
SimpleUrlHandlerMapping类
该类只有一个核心属性urlMap,用于存储url和handler的映射关系
private final Map<String, Object> urlMap = new LinkedHashMap<String, Object>();
initApplicationContext
因为该类间接实现了WebApplicationObjectSupport,所以该类重写了该方法。方法内容主要是初始化url和handler的映射关系,用于后续使用过程中的request请求映射。
@Overridepublic void initApplicationContext() throws BeansException {//调用父类的initApplicationContext()方法,设置相关的拦截器super.initApplicationContext();//核心方法注册相关urlMapregisterHandlers(this.urlMap);}
registerHandler
SimpleUrlHandlerMapping类重写了父类的registerHandler方法
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {if (urlMap.isEmpty()) {logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");}else {//遍历urlMap 对url进行处理for (Map.Entry<String, Object> entry : urlMap.entrySet()) {String url = entry.getKey();Object handler = entry.getValue();// 如果没有‘/’前缀,则添加前缀‘/’if (!url.startsWith("/")) {url = "/" + url;}// Remove whitespace from handler bean name.if (handler instanceof String) {handler = ((String) handler).trim();}//调用父类注册的核心方法最终将其存储在handlerMap集合registerHandler(url, handler);}}}
SimpleUrlHandlerMapping很简单,几乎所有的核心方法都在父类中,SimpleHandlerMapping只是用于做url映射的初始化,这种映射是直接匹配的形式,即通过request解析出其中的urlPath,根据urlPath路径直接从handlerMap中获取urlPath匹配的Handler对象。
AbstractDetectingUrlHandlerMapping类
AbstractDetectingUrlHandlerMapping类和上面SimpleUrlHandlerMapping的结构相关,都是重写了其中的initApplicationContext()方法,只是其注册逻辑不是需要显示的设置相关的url而是从spring容器中获取所有的bean实例,通过其BeanName(Handler对象)获取其匹配的url列表。
detectHandlers
该方法获取所有的beanName并获取其url列表后进行注册。
@Overridepublic void initApplicationContext() throws ApplicationContextException {super.initApplicationContext();detectHandlers();}protected void detectHandlers() throws BeansException {if (logger.isDebugEnabled()) {logger.debug("Looking for URL mappings in application context: " + getApplicationContext());}//detectHandlersInAncestorContexts true 则获取其容器和父容器中所有的bean实例对象//为false 则只从当前容器对象中获取bean实例String[] beanNames = (this.detectHandlersInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :getApplicationContext().getBeanNamesForType(Object.class));//遍历所有的beanName 根据beanName获取其逻辑匹配的urls 然后调用父类的registerHandler()方法注册相关的映射关系for (String beanName : beanNames) {//交由子类实现根据beanName获取url列表String[] urls = determineUrlsForHandler(beanName);if (!ObjectUtils.isEmpty(urls)) {registerHandler(urls, beanName);}else {if (logger.isDebugEnabled()) {logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");}}}}
BeanNameUrlHandlerMapping#determineUrlsForHandler
@Overrideprotected String[] determineUrlsForHandler(String beanName) {List<String> urls = new ArrayList<String>();//使用beanName 作为urlif (beanName.startsWith("/")) {urls.add(beanName);}String[] aliases = getApplicationContext().getAliases(beanName);//bean实例的所有别名作为urlfor (String alias : aliases) {if (alias.startsWith("/")) {urls.add(alias);}}return StringUtils.toStringArray(urls);}
本文我们整理了HandlerMapping接口、AbstractHandlerMapping类、AbstractUrlHandlerMapping类,介绍了URL与类对应关系的映射注册,下文我们将介绍AbstractHandlerMethodMapping类与我们最常用的实现类RequestMappingHandlerMapping。
相关文章:

SpringMVC源码:HandlerMapping加载1
参考资料: 《SpringMVC源码解析系列》 《SpringMVC源码分析》 《Spring MVC源码》 写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。 前文: 《SpringMVC源码&a…...
【ArcGIS】12 投影
问题描述 在处理地理数据时,可能会遇到以下关于投影的问题: DEM缺少投影,提取流域会报错图层只有地理坐标系,没有投影坐标系,无法测量距离、计算面积等要素图层投影偏移量错误,与实际位置有偏差总之,投影对各种地理操作影响很大,有必要深入理解。 投影说明 在ArcGIS…...

【微信小程序-原生开发+TDesign】通用功能页封装——地点搜索(含腾讯地图开发key 的申请方法)
效果预览 核心技能点 调用腾讯地图官方的关键字地点搜索功能,详见官方文档 https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/methodGetsuggestion 完整代码实现 地点输入框 <t-input value"{{placeInfo.title}}" bindtap"searchPlace" dis…...

h5: 打开手机上的某个app
1、android端:直接通过URL Scheme方式打开。2、ios端(2种):(1)使用URL Scheme方式打开。(2)使用Universal link方式打开。3、Universal link方式使用注意事项:࿰…...

Hot Chocolate 构建 GraphQL .Net Core 服务
Hot Chocolate 是 .NET 平台下的一个开源组件库, 您可以使用它创建 GraphQL 服务, 它消除了构建成熟的 GraphQL 服务的复杂性, Hot Chocolate 可以连接任何服务或数据源,并创建一个有凝聚力的服务,为您的消费者提供统一的 API。 我会在 .NET 应用中使用…...
linux shell 入门学习笔记16 流程控制开发
shell的流程控制一般包括if、for、while、case/esac、until、break、continue语句构成。 if语句开发 单分支if //方式1 if <条件表达式> then 代码。。。 fi //方式2 if <条件表达式>;then 代码。。。 fi 双分支if if <条件表达式> then 代码1 if <条件表…...

机器学习:基于朴素贝叶斯对花瓣花萼的宽度和长度分类预测
机器学习:基于朴素贝叶斯对花瓣花萼的宽度和长度分类预测 作者:AOAIYI 作者简介:Python领域新星作者、多项比赛获奖者:AOAIYI首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞…...
给VivoBook扩容重装系统
现在笔记本重装系统都这么复杂吗?原谅我还是10年前的装机水平,折腾了一天终于把系统重新安装好了。 笔记本: ASUS VivoBook 安装系统: Win10 1、扩容 电脑配的512G硬盘满了要换个大的,后盖严丝合缝,不…...

vue 依赖注入使用教程
vue 中的依赖注入,官网文档已经非常详细,笔者在这里总结一份 目录 1、背景介绍 2、代码实现 2.1、依赖注入固定值 2.2、 依赖注入响应式数据 3、注入别名 4、注入默认值 5、应用层 Provide 6、使用 Symbol 作注入名 1、背景介绍 为什么会出现依…...

【再临数据结构】Day1. 稀疏数组
前言 这不单单是稀疏数组的开始,也是我重学数据结构的开始。因此,在开始说稀疏数组的具体内容之前,我想先说一下作为一个有着十余年“学龄”的学生,所一直沿用的一个学习方法:3W法。我认为,只有掌握了正确的…...
二十四、MongoDB 聚合运算( aggregate )
MongoDB 聚合( aggregate ) 用于处理数据,比如统计平均值,求和等。然后返回计算后的数据结果 MongoDB 聚合有点类似 SQL 语句中的 COUNT( * ) aggregate() 方法 MongoDB aggregate() 为 MongoDB 数据库提供了聚合运算 语法 aggregate() 方法的语法如下 > d…...
【C++】6.模板初阶
交换两个数 任何一个类型交换还要重新写一个函数 如何解决? 模板->写跟类型无关的函数 1.泛型编程 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。 如何写一个函数适用所有类型的交换? #include &…...
Docker部署Airbyte
Linux环境部署前置要求机器配置2c4g(最低),4c8g(推荐)dockerdocker-compose (要求新版本的docker-compose)安装airbyte,打开终端,进入你想安装airbyte的目录。#Clone代码 git clone https://github.com/air…...

2023王道考研数据结构笔记第一章绪论
第一章 绪论 1.1 数据结构的基本概念 1.数据:数据是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别和处理的符号的集合。 2.数据元素:数据元素是数据的基本单位,通常作为一个整体进行考虑和处理…...

告别空指针让代码变优雅,Optional使用图文例子源码解读
一、前言 我们在开发中最常见的异常就是NullPointerException,防不胜防啊,相信大家肯定被坑过! 这种基本出现在获取数据库信息中、三方接口,获取的对象为空,再去get出现! 解决方案当然简单,只…...

【C++】哈希——unordered系列容器|哈希冲突|闭散列|开散列
文章目录一、unordered系列关联式容器二、哈希概念三、哈希冲突四、哈希函数五、解决哈希冲突1.闭散列——开放定址法2.代码实现3.开散列——开链法4.代码实现六、结语一、unordered系列关联式容器 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,…...
mysql-面试
锁: mysql的锁分为全局锁、表锁、行锁、间隙锁 全局锁:Flush tables with read lock 可以全局设计库为只读 表锁:一种是表锁,一种是元数据锁(meta data lock,MDL) lock tables t1 read,t2 wi…...

【夏虫语冰】Win10局域网下两台电脑无法ping通: 无法访问目标主机
文章目录1、简介2、修改高级共享设置3、启用防火墙规则4、局域网内的其他主机访问NAT模式下的虚拟机4.1 虚拟机网络设置4.2 访问测试4.2.1 http测试4.2.2 curl测试4.2.3 telnet测试4.2.4 端口占用测试5、其他结语1、简介 ping 192.168.31.134ping主机ip时,访问无法…...

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——Join多种应用
3.7.1Reduce Join 1、工作原理 Map端的主要工作:为来自不同表或文件的key/value对,打标签以区别不同来源的记录。然后用连接字段作为key,其余部分和新加的标志作为value,最后进行输出。 Reduce端的主要工作:在Reduc…...

SSRF漏洞原理、危害以及防御与修复
一、SSRF漏洞原理漏洞概述SSRF(Server-side Request Forge,服务端请求伪造)是一种由攻击者构造形成由服务端发起请求的安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。正是因为它是由服务端发起的,所…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...