当前位置: 首页 > news >正文

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

参考资料&#xff1a; 《SpringMVC源码解析系列》 《SpringMVC源码分析》 《Spring MVC源码》 写在开头&#xff1a;本文为个人学习笔记&#xff0c;内容比较随意&#xff0c;夹杂个人理解&#xff0c;如有错误&#xff0c;欢迎指正。 前文&#xff1a; 《SpringMVC源码&a…...

【ArcGIS】12 投影

问题描述 在处理地理数据时,可能会遇到以下关于投影的问题: DEM缺少投影,提取流域会报错图层只有地理坐标系,没有投影坐标系,无法测量距离、计算面积等要素图层投影偏移量错误,与实际位置有偏差总之,投影对各种地理操作影响很大,有必要深入理解。 投影说明 在ArcGIS…...

【微信小程序-原生开发+TDesign】通用功能页封装——地点搜索(含腾讯地图开发key 的申请方法)

效果预览 核心技能点 调用腾讯地图官方的关键字地点搜索功能&#xff0c;详见官方文档 https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/methodGetsuggestion 完整代码实现 地点输入框 <t-input value"{{placeInfo.title}}" bindtap"searchPlace" dis…...

h5: 打开手机上的某个app

1、android端&#xff1a;直接通过URL Scheme方式打开。2、ios端&#xff08;2种&#xff09;&#xff1a;&#xff08;1&#xff09;使用URL Scheme方式打开。&#xff08;2&#xff09;使用Universal link方式打开。3、Universal link方式使用注意事项&#xff1a;&#xff0…...

Hot Chocolate 构建 GraphQL .Net Core 服务

Hot Chocolate 是 .NET 平台下的一个开源组件库, 您可以使用它创建 GraphQL 服务, 它消除了构建成熟的 GraphQL 服务的复杂性, Hot Chocolate 可以连接任何服务或数据源&#xff0c;并创建一个有凝聚力的服务&#xff0c;为您的消费者提供统一的 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 <条件表…...

机器学习:基于朴素贝叶斯对花瓣花萼的宽度和长度分类预测

机器学习&#xff1a;基于朴素贝叶斯对花瓣花萼的宽度和长度分类预测 作者&#xff1a;AOAIYI 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;AOAIYI首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞…...

给VivoBook扩容重装系统

现在笔记本重装系统都这么复杂吗&#xff1f;原谅我还是10年前的装机水平&#xff0c;折腾了一天终于把系统重新安装好了。 笔记本&#xff1a; ASUS VivoBook 安装系统&#xff1a; Win10 1、扩容 电脑配的512G硬盘满了要换个大的&#xff0c;后盖严丝合缝&#xff0c;不…...

vue 依赖注入使用教程

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

【再临数据结构】Day1. 稀疏数组

前言 这不单单是稀疏数组的开始&#xff0c;也是我重学数据结构的开始。因此&#xff0c;在开始说稀疏数组的具体内容之前&#xff0c;我想先说一下作为一个有着十余年“学龄”的学生&#xff0c;所一直沿用的一个学习方法&#xff1a;3W法。我认为&#xff0c;只有掌握了正确的…...

二十四、MongoDB 聚合运算( aggregate )

MongoDB 聚合( aggregate ) 用于处理数据&#xff0c;比如统计平均值,求和等。然后返回计算后的数据结果 MongoDB 聚合有点类似 SQL 语句中的 COUNT( * ) aggregate() 方法 MongoDB aggregate() 为 MongoDB 数据库提供了聚合运算 语法 aggregate() 方法的语法如下 > d…...

【C++】6.模板初阶

交换两个数 任何一个类型交换还要重新写一个函数 如何解决&#xff1f; 模板->写跟类型无关的函数 1.泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础。 如何写一个函数适用所有类型的交换? #include &…...

Docker部署Airbyte

Linux环境部署前置要求机器配置2c4g(最低)&#xff0c;4c8g&#xff08;推荐&#xff09;dockerdocker-compose &#xff08;要求新版本的docker-compose&#xff09;安装airbyte,打开终端&#xff0c;进入你想安装airbyte的目录。#Clone代码 git clone https://github.com/air…...

2023王道考研数据结构笔记第一章绪论

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

告别空指针让代码变优雅,Optional使用图文例子源码解读

一、前言 我们在开发中最常见的异常就是NullPointerException&#xff0c;防不胜防啊&#xff0c;相信大家肯定被坑过&#xff01; 这种基本出现在获取数据库信息中、三方接口&#xff0c;获取的对象为空&#xff0c;再去get出现&#xff01; 解决方案当然简单&#xff0c;只…...

【C++】哈希——unordered系列容器|哈希冲突|闭散列|开散列

文章目录一、unordered系列关联式容器二、哈希概念三、哈希冲突四、哈希函数五、解决哈希冲突1.闭散列——开放定址法2.代码实现3.开散列——开链法4.代码实现六、结语一、unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c…...

mysql-面试

锁&#xff1a; mysql的锁分为全局锁、表锁、行锁、间隙锁 全局锁&#xff1a;Flush tables with read lock 可以全局设计库为只读 表锁&#xff1a;一种是表锁&#xff0c;一种是元数据锁&#xff08;meta data lock&#xff0c;MDL&#xff09; 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时&#xff0c;访问无法…...

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——Join多种应用

3.7.1Reduce Join 1、工作原理 Map端的主要工作&#xff1a;为来自不同表或文件的key/value对&#xff0c;打标签以区别不同来源的记录。然后用连接字段作为key&#xff0c;其余部分和新加的标志作为value&#xff0c;最后进行输出。 Reduce端的主要工作&#xff1a;在Reduc…...

SSRF漏洞原理、危害以及防御与修复

一、SSRF漏洞原理漏洞概述SSRF&#xff08;Server-side Request Forge&#xff0c;服务端请求伪造&#xff09;是一种由攻击者构造形成由服务端发起请求的安全漏洞。一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。正是因为它是由服务端发起的&#xff0c;所…...

CV学习笔记-ResNet

ResNet 文章目录ResNet1. ResNet概述1.1 常见卷积神经网络1.2 ResNet提出背景2. ResNet网络结构2.1 Residual net2.2 残差神经单元2.3 Shortcut2.4 ResNet50网络结构3. 代码实现3.1 Identity Block3.2 Conv Block3.3 ResNet网络定义3.4 整体代码测试1. ResNet概述 1.1 常见卷积…...

百亿数据,毫秒级返回查询优化

近年来公司业务迅猛发展&#xff0c;数据量爆炸式增长&#xff0c;随之而来的的是海量数据查询等带来的挑战&#xff0c;我们需要数据量在十亿&#xff0c;甚至百亿级别的规模时依然能以秒级甚至毫秒级的速度返回&#xff0c;这样的话显然离不开搜索引擎的帮助&#xff0c;在搜…...

cpp之STL

STL原理 STL ⼀共提供六⼤组件&#xff0c;包括容器&#xff0c;算法&#xff0c;迭代器&#xff0c;仿函数&#xff0c;适配器和空间配置器&#xff0c;彼此可以组合套⽤。容器通过配置器取得数据存储空间&#xff0c;算法通过迭代器存取容器内容&#xff0c;仿函数可以协助算…...

基于Spring Boot开发的资产管理系统

文章目录 项目介绍主要功能截图:登录首页信息软件管理服务器管理网络设备固定资产明细硬件管理部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目…...

Markdown总结

文字的着重标记与段落的层次划分 Tab键可以缩进列表&#xff1b; shift Tab&#xff1a;取消缩进列表 加粗&#xff08;****&#xff09;、斜体&#xff08;**&#xff09;高亮&#xff1a;xxx$$&#xff1a;特殊标记删除&#xff1a;~~xxx~~多级标题&#xff1a;######无序列…...

字节跳动软件测试岗4轮面经(已拿34K+ offer)...

没有绝对的天才&#xff0c;只有持续不断的付出。对于我们每一个平凡人来说&#xff0c;改变命运只能依靠努力幸运&#xff0c;但如果你不够幸运&#xff0c;那就只能拉高努力的占比。 2021年10月&#xff0c;我有幸成为了字节跳动的一名测试工程师&#xff0c;从外包辞职了历…...

docker - 搭建redis集群和Etcd

概述 由于业务需要&#xff0c;需要把之前的分布式架构调整成微服务&#xff0c;把老项目迁移到k8s的服务中&#xff0c;再开始编码之前&#xff0c;需要再本地环境里做相应的准备工作&#xff0c;使用docker搭建redis集群&#xff0c;Etcd主要是注册本地的rpc服务。 Liunx O…...

Java程序开发中如何使用lntelliJ IDEA?

完成了IDEA的安装与启动&#xff0c;下面使用IDEA创建一个Java程序&#xff0c;实现在控制台上打印HelloWorld!的功能&#xff0c;具体步骤如下。 1.创建Java项目 进入New Project界面后&#xff0c;单击New Project选项按钮创建新项目&#xff0c;弹出New Project对话框&…...

【Linux】理解进程地址空间

&#x1f34e;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Linux系统编程 ​我们在学习C语言的时候&#xff0c;都学过内存区域的划分如栈、堆、代码区、数据区这些。但我们其实并不真正理解内存 — 我们之前一直说的内存是物理上的内存吗&#xff1f; 前言 我们…...

Unity脚本 --- 常用API(类)--- GameObject类 和

第一部分 --- GameObject类 1.在Hierarchy 层级面板中添加游戏物体其实就相当于在场景中添加游戏物体 2.每一个场景都有一个自己的Hierarchy层级面板&#xff0c;用来管理场景中的所有游戏物体 3.是的&#xff0c;我们可以创建多个场景 1.首先上面这两个变量都是布尔变量&am…...

wordpress自定义结构404/营销策划

1.前言 TreeMap对应的线程安全是ConcurrentSkipListMapHashMap对应的线程安全是ConcurrentHashMap 2.concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下&#xff0c;ConcurrentHashMap 存取速度是ConcurrentSkipListMap 的4倍左右。 但Concurrent…...

常州孟河镇建设工程交易网站/链接

scala中的基本控制结构&#xff1a;1.顺序2.条件3.循环&#xff0c;和其他的JVM语言是一致的。 scala也有一些高级的控制结构&#xff0c;例如模式匹配。 if条件表达式会根据if后面括号里面的boolean来决定整个if表达式的值 1.scala中的if表达式是有返回值的&#xff01;这点…...

php可以做网站app吗/如何快速提升网站关键词排名

出现这种错误的原因就是&#xff1a;你入参的数值超过了数据库中定义的类型长度&#xff0c;这时候需要修改数据库中的类型了。...

手机网站免费做推广/百度客服中心

负margin理论&#xff1a; 何谓参考线&#xff1f;参考线就是 margin移动的基准点&#xff0c;此基准点相对于box(自身)是静止的。而margin的数值&#xff0c;就是box相对于参考线的位移量。 一个完整的margin属性是这么写的margin: top right bottom left;(eg: margin:10px 20…...

网站备案查询工信部手机版/精美软文句子

文章目录前言一、Gradio是什么&#xff1f;二、使用Gradio构建基本的 Web 应用三、使用Gradio构建彩色图片转灰度图片的Web 应用四、使用Gradio构建验证码识别方法验证的Web 应用总结前言 随着人工智能的不断发展&#xff0c;各种智能算法越来越普遍&#xff0c;但是这些算法结…...

网上的彩票网站是怎么做的/推广公司好做吗

1. 等价类划分 常见的软件测试面试题划分等价类: 等价类是指某个输入域的子集合.在该子集合中,各个输入数据对于揭露程序中的错误都是等效的.并合理地假定:测试某等价类的代表值就等于对这一类其它值的测试.因此,可以把全部输入数据合理划分为假设干等价类,在每一个等价类中取一…...