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攻击的目标是从外网无法访问的内部系统。正是因为它是由服务端发起的,所…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
AD学习(3)
1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分: (1)PCB焊盘:表层的铜 ,top层的铜 (2)管脚序号:用来关联原理图中的管脚的序号,原理图的序号需要和PCB封装一一…...
负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
Python的__call__ 方法
在 Python 中,__call__ 是一个特殊的魔术方法(magic method),它允许一个类的实例像函数一样被调用。当你在一个对象后面加上 () 并执行时(例如 obj()),Python 会自动调用该对象的 __call__ 方法…...
