Feign原理 (图解)

article/2025/9/2 13:33:22

1.1 简介:Feign远程调用的

 

 

Feign远程调用,核心就是通过一系列的封装和处理,将以JAVA注解的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVA Bean,放回给调用者。Feign远程调用的基本流程,大致如下图所示。

 

å¨è¿éæå¥å¾çæè¿°

从上图可以看到,Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的 Request 请求。通过Feign以及JAVA的动态代理机制,使得Java 开发人员,可以不用通过HTTP框架去封装HTTP请求报文的方式,完成远程服务的HTTP调用。

 

1.2 Feign 远程调用的重要组件

 

在微服务启动时,Feign会进行包扫描,对加@FeignClient注解的接口,按照注解的规则,创建远程接口的本地JDK Proxy代理实例。然后,将这些本地Proxy代理实例,注入到Spring IOC容器中。当远程接口的方法被调用,由Proxy代理实例去完成真正的远程访问,并且返回结果。

为了清晰的介绍SpringCloud中Feign运行机制和原理,在这里,首先为大家梳理一下Feign中几个重要组件。

 

1.2.1 远程接口的本地JDK Proxy代理实例

 

远程接口的本地JDK Proxy代理实例,有以下特点:

(1)Proxy代理实例,实现了一个加 @FeignClient 注解的远程调用接口;

(2)Proxy代理实例,能在内部进行HTTP请求的封装,以及发送HTTP 请求;

(3)Proxy代理实例,能处理远程HTTP请求的响应,并且完成结果的解码,然后返回给调用者。

下面以一个简单的远程服务的调用接口 DemoClient 为例,具体介绍一下远程接口的本地JDK Proxy代理实例的创建过程。

DemoClient 接口,有两个非常简单的远程调用抽象方法:一个为hello() 抽象方法,用于完成远程URL “/api/demo/hello/v1”的HTTP请求;一个为 echo(…) 抽象方法,用于完成远程URL “/api/demo/echo/{word}/v1”的HTTP请求。具体如下图所示。

 

å¨è¿éæå¥å¾çæè¿°

 

DemoClient 接口代码如下:

 

       package com.crazymaker.springcloud.demo.contract.client;
//…省略import@FeignClient(value = "seckill-provider", path = "/api/demo/",fallback = DemoDefaultFallback.class)public interface DemoClient {/*** 测试远程调用** @return hello*/@GetMapping("/hello/v1")Result<JSONObject> hello();/*** 非常简单的一个 回显 接口,主要用于远程调用** @return echo 回显消息*/@RequestMapping(value = "/echo/{word}/v1", method = RequestMethod.GET)Result<JSONObject> echo(@PathVariable(value = "word") String word);}

 

 

注意,上面的代码中,在DemoClient 接口上,加有@FeignClient 注解。也即是说,Feign在启动时,会为其创建一个本地JDK Proxy代理实例,并注册到Spring IOC容器。

如何使用呢?可以通过@Resource注解,按照类型匹配(这里的类型为DemoClient接口类型),从Spring IOC容器找到这个代理实例,并且装配给需要的成员变量。

DemoClient的 本地JDK Proxy 代理实例的使用的代码如下:

 

package com.crazymaker.springcloud.user.info.controller;
//…省略import@Api(value = "用户信息、基础学习DEMO", tags = {"用户信息、基础学习DEMO"})@RestController@RequestMapping("/api/user")public class UserController {@ResourceDemoClient demoClient;  //装配 DemoClient 的本地代理实例@GetMapping("/say/hello/v1")@ApiOperation(value = "测试远程调用速度")public Result<JSONObject> hello() {Result<JSONObject> result = demoClient.hello();JSONObject data = new JSONObject();data.put("others", result);return Result.success(data).setMsg("操作成功");}
//…}

 

DemoClient的本地JDK Proxy代理实例的创建过程,比较复杂,稍后作为重点介绍。先来看另外两个重要的逻辑组件。

1.2.2 调用处理器 InvocationHandler

默认的调用处理器 FeignInvocationHandler 是一个相对简单的类,有一个非常重要Map类型成员 dispatch 映射,保存着远程接口方法到MethodHandler方法处理器的映射。

以前面示例中DemoClient 接口为例,其代理实现类的调用处理器 FeignInvocationHandler 的dispatch 成员的内存结构图如图3所示。

 

å¨è¿éæå¥å¾çæè¿°

 

1.2.1 默认的调用处理器 FeignInvocationHandler

 

å¨è¿éæå¥å¾çæè¿°

 

为何在图3中的Map类型成员 dispatch 映射对象中,有两个Key-Value键值对呢?

原因是:默认的调用处理器 FeignInvocationHandle,在处理远程方法调用的时候,会根据Java反射的方法实例,在dispatch 映射对象中,找到对应的MethodHandler 方法处理器,然后交给MethodHandler 完成实际的HTTP请求和结果的处理。前面示例中的 DemoClient 远程调用接口,有两个远程调用方法,所以,其代理实现类的调用处理器 FeignInvocationHandler 的dispatch 成员,有两个有两个Key-Value键值对。

FeignInvocationHandler的关键源码,节选如下:

package feign;
//...省略importpublic class ReflectiveFeign extends Feign {//...//内部类:默认的Feign调用处理器 FeignInvocationHandlerstatic class FeignInvocationHandler implements InvocationHandler {private final Target target;//方法实例对象和方法处理器的映射private final Map<Method, MethodHandler> dispatch;//构造函数    FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {this.target = checkNotNull(target, "target");this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);}//默认Feign调用的处理@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//...//首先,根据方法实例,从方法实例对象和方法处理器的映射中,//取得 方法处理器,然后,调用 方法处理器 的 invoke(...) 方法return dispatch.get(method).invoke(args);}//...}

 

源码很简单,重点在于invoke(…)方法,虽然核心代码只有一行,但是其功能是复杂的:

(1)根据Java反射的方法实例,在dispatch 映射对象中,找到对应的MethodHandler 方法处理器;

(2)调用MethodHandler方法处理器的 invoke(...) 方法,完成实际的HTTP请求和结果的处理。

补充说明一下:MethodHandler 方法处理器,和JDK 动态代理机制中位于 java.lang.reflect 包的 InvocationHandler 调用处理器接口,没有任何的继承和实现关系。MethodHandler 仅仅是Feign自定义的,一个非常简单接口。

 

 

1.2.2 方法处理器 MethodHandler

 

Feign的方法处理器 MethodHandler 是一个独立的接口,定义在 InvocationHandlerFactory 接口中,仅仅拥有一个invoke(…)方法,源码如下:

 

//定义在InvocationHandlerFactory接口中public interface InvocationHandlerFactory {//…//方法处理器接口,仅仅拥有一个invoke(…)方法interface MethodHandler {//完成远程URL请求Object invoke(Object[] argv) throws Throwable;}
//...}

 

MethodHandler 的invoke(…)方法,主要职责是完成实际远程URL请求,然后返回解码后的远程URL的响应结果。Feign提供了默认的 SynchronousMethodHandler 实现类,提供了基本的远程URL的同步请求处理。有关 SynchronousMethodHandler类以及其与MethodHandler的关系,大致如图4所示。

 

å¨è¿éæå¥å¾çæè¿°

为了彻底了解方法处理器,来读一下 SynchronousMethodHandler 方法处理器的源码,如下:

SynchronousMethodHandler(重中之重)

同步方法调用处理器,它强调的是同步二字,且有远程通信。

final class SynchronousMethodHandler implements MethodHandler {// 方法元信息private final MethodMetadata metadata;// 目标  也就是最终真正构建Http请求Request的实例 一般为HardCodedTargetprivate final Target<?> target;// 负责最终请求的发送 -> 默认传进来的是基于JDK源生的,效率很低,不建议直接使用private final Client client;// 负责重试 -->默认传进来的是Default,是有重试机制的哦,生产上使用请务必注意private final Retryer retryer;// 请求拦截器,它会在target.apply(template); 也就是模版 -> 请求的转换之前完成拦截// 说明:并不是发送请求之前那一刻哦,请务必注意啦// 它的作用只能是对请求模版做定制,而不能再对Request做定制了// 内置仅有一个实现:BasicAuthRequestInterceptor 用于鉴权private final List<RequestInterceptor> requestInterceptors;// 若你想在控制台看到feign的请求日志,改变此日志级别为info吧(因为一般只有info才会输出到日志文件)private final Logger.Level logLevel;...// 构建请求模版的工厂// 对于请求模版,有多种构建方式,内部会用到可能多个编码器,下文详解private final RequestTemplate.Factory buildTemplateFromArgs;// 请求参数:比如链接超时时间、请求超时时间等private final Options options;// 解码器:用于对Response进行解码private final Decoder decoder;// 发生错误/异常时的解码器private final ErrorDecoder errorDecoder;// 是否解码404状态码?默认是不解码的private final boolean decode404;// 唯一的构造器,并且还是私有的(所以肯定只能在本类内构建出它的实例喽)// 完成了对如上所有属性的赋值private SynchronousMethodHandler( ... ) { ... }@Overridepublic Object invoke(Object[] argv) throws Throwable {// 根据方法入参,结合工厂构建出一个请求模版RequestTemplate template = buildTemplateFromArgs.create(argv);// findOptions():如果你方法入参里含有Options类型这里会被找出来// 说明:若有多个只会有第一个生效(不会报错)Options options = findOptions(argv);// 重试机制:注意这里是克隆一个来使用Retryer retryer = this.retryer.clone();while (true) {try {return executeAndDecode(template, options);} catch (RetryableException e) {// 若抛出异常,那就触发重试逻辑try {// 该逻辑是:如果不重试了,该异常会继续抛出// 若要充值,就会走下面的continueretryer.continueOrPropagate(e);} catch (RetryableException th) {...}continue;}}}
}

 

MethodHandler实现相对复杂,用一句话描述便是:准备好所有参数后,发送Http请求,并且解析结果。它的步骤我尝试总结如下:

  1. 通过方法参数,使用工厂构建出一个RequestTemplate请求模版
    1. 这里会解析@RequestLine/@Param等等注解
  2. 从方法参数里拿到请求选项:Options(当然参数里可能也没有此类型,那就是null喽。如果是null,那最终执行默认的选项)
  3. executeAndDecode(template, options)执行发送Http请求,并且完成结果解码(包括正确状态码的解码和错误解码)。这个步骤比较复杂,拆分为如下子步骤:
    1. 把请求模版转换为请求对象feign.Request
      1. 执行所有的拦截器RequestInterceptor,完成对请求模版的定制
      2. 调用目标target,把请求模版转为Request:target.apply(template);
    2. 发送Http请求:client.execute(request, options),得到一个Response对象(这里若发生IO异常,也会被包装为RetryableException重新抛出)
    3. 解析此Response对象,解析后return(返回Object:可能是Response实例,也可能是decode解码后的任意类型)。大致会有如下情况:
      1. Response.class == metadata.returnType(),也就是说你的方法返回值用的就是Response。若response.body() == null,也就是说服务端是返回null/void的话,就直接return response;若response.body().length() == null,就直接返回response;否则,就正常返回response.toBuilder().body(bodyData).build() body里面的内容吧
      2. 200 <= 响应码 <= 300,表示正确的返回。那就对返回值解码即可:decoder.decode(response, metadata.returnType())(解码过程中有可能异常,也会被包装成FeignException向上抛出)
      3. 若响应码是404,并且decode404 = true,那同上也同样执行decode动作
      4. 其它情况(4xx或者5xx的响应码),均执行错误编码:errorDecoder.decode(metadata.configKey(), response)
  4. 发送http请求若一切安好,那就结束了。否则执行重试逻辑:
    1. 通过retryer.continueOrPropagate(e);看看收到此异常后是否要执行重试机制
    2. 需要重试的话就continue(注意上面是while(true)哦~)
    3. 若不需要重试(或者重试次数已到),那就重新抛出此异常,向上抛出
    4. 处理此异常,打印日志…
  5. 1.2.3 Feign 客户端组件 feign.Client

    客户端组件是Feign中一个非常重要的组件,负责端到端的执行URL请求。其核心的逻辑:发送request请求到服务器,并接收response响应后进行解码。

    feign.Client 类,是代表客户端的顶层接口,只有一个抽象方法,源码如下:

    package feign;/**客户端接口* Submits HTTP {@link Request requests}. 
    Implementations are expected to be thread-safe.*/
    public interface Client {//提交HTTP请求,并且接收response响应后进行解码Response execute(Request request, Options options) throws IOException;}

    由于不同的feign.Client 实现类,内部完成HTTP请求的组件和技术不同,故,feign.Client 有多个不同的实现。这里举出几个例子:

    (1)Client.Default类:默认的feign.Client 客户端实现类,内部使用HttpURLConnnection 完成URL请求处理;

    (2)ApacheHttpClient 类:内部使用 Apache httpclient 开源组件完成URL请求处理的feign.Client 客户端实现类;

    (3)OkHttpClient类:内部使用 OkHttp3 开源组件完成URL请求处理的feign.Client 客户端实现类。

    (4)LoadBalancerFeignClient 类:内部使用 Ribben 负载均衡技术完成URL请求处理的feign.Client 客户端实现类。

    此外,还有一些特殊场景使用的feign.Client客户端实现类,也可以定制自己的feign.Client实现类。下面对上面几个常见的客户端实现类,进行简要介绍。
    在这里插入图片描述

    ​ 图6 feign.Client客户端实现类

    一:Client.Default类:

    作为默认的Client 接口的实现类,在Client.Default内部使用JDK自带的HttpURLConnnection类实现URL网络请求。

    图片

    ​ 图7 默认的Client 接口的客户端实现类

    在JKD1.8中,虽然在HttpURLConnnection 底层,使用了非常简单的HTTP连接池技术,但是,其HTTP连接的复用能力,实际是非常弱的,性能当然也很低。具体的原因,参见后面的“SpringCloud与长连接的深入剖析”专题内容。

    二:ApacheHttpClient类

    ApacheHttpClient 客户端类的内部,使用 Apache HttpClient开源组件完成URL请求的处理。

    从代码开发的角度而言,Apache HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性,它不仅使客户端发送Http请求变得容易,而且也方便开发人员测试接口。既提高了开发的效率,也方便提高代码的健壮性。

    从性能的角度而言,Apache HttpClient带有连接池的功能,具备优秀的HTTP连接的复用能力。关于带有连接池Apache HttpClient的性能提升倍数,具体可以参见后面的对比试验。

    ApacheHttpClient 类处于 feign-httpclient 的专门jar包中,如果使用,还需要通过Maven依赖或者其他的方式,倒入配套版本的专门jar包。

    三:OkHttpClient类

    OkHttpClient 客户端类的内部,使用OkHttp3 开源组件完成URL请求处理。OkHttp3 开源组件由Square公司开发,用于替代HttpUrlConnection和Apache HttpClient。由于OkHttp3较好的支持 SPDY协议(SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。),从Android4.4开始,google已经开始将Android源码中的 HttpURLConnection 请求类使用OkHttp进行了替换。也就是说,对于Android 移动端APP开发来说,OkHttp3 组件,是基础的开发组件之一。

    四:LoadBalancerFeignClient 类

    LoadBalancerFeignClient 内部使用了 Ribben 客户端负载均衡技术完成URL请求处理。在原理上,简单的使用了delegate包装代理模式:Ribben负载均衡组件计算出合适的服务端server之后,由内部包装 delegate 代理客户端完成到服务端server的HTTP请求;所封装的 delegate 客户端代理实例的类型,可以是 Client.Default 默认客户端,也可以是 ApacheHttpClient 客户端类或OkHttpClient 高性能客户端类,还可以其他的定制的feign.Client 客户端实现类型。

    LoadBalancerFeignClient 负载均衡客户端实现类,具体如下图所示。
    在这里插入图片描述

    ​ 图8 LoadBalancerFeignClient 负载均衡客户端实现类

    1.1 Feigh 远程调用的执行流程

    由于Feign远程调用接口的JDK Proxy实例的InvokeHandler调用处理器有多种,导致Feign远程调用的执行流程,也稍微有所区别,但是远程调用执行流程的主要步骤,是一致的。这里主要介绍两类JDK Proxy实例的InvokeHandler调用处理器相关的远程调用执行流程:

    (1)与 默认的调用处理器 FeignInvocationHandler 相关的远程调用执行流程;

    (2)与 Hystrix调用处理器 HystrixInvocationHandler 相关的远程调用执行流程。

    介绍过程中,还是以前面的DemoClient的JDK Proxy远程动态代理实例的执行过程为例,演示分析Feigh远程调用的执行流程。

    1.1.1 与 FeignInvocationHandler 相关的远程调用执行流程

    FeignInvocationHandler是默认的调用处理器,如果不对Feign做特殊的配置,则Feign将使用此调用处理器。结合前面的DemoClient的JDK Proxy远程动态代理实例的hello()远程调用执行过程,在这里,详细的介绍一下与 FeignInvocationHandler 相关的远程调用执行流程,大致如下图所示。
    在这里插入图片描述

    ​ 图6 与 FeignInvocationHandler 相关的远程调用执行流程

    整体的远程调用执行流程,大致分为4步,具体如下:

    第1步:通过Spring IOC 容器实例,装配代理实例,然后进行远程调用。

    前文讲到,Feign在启动时,会为加上了@FeignClient注解的所有远程接口(包括 DemoClient 接口),创建一个本地JDK Proxy代理实例,并注册到Spring IOC容器。在这里,暂且将这个Proxy代理实例,叫做 DemoClientProxy,稍后,会详细介绍这个Proxy代理实例的具体创建过程。

    然后,在本实例的UserController 调用代码中,通过@Resource注解,按照类型或者名称进行匹配(这里的类型为DemoClient接口类型),从Spring IOC容器找到这个代理实例,并且装配给@Resource注解所在的成员变量,本实例的成员变量的名称为 demoClient。

    在需要代进行hello()远程调用时,直接通过 demoClient 成员变量,调用JDK Proxy动态代理实例的hello()方法。

    第2步:执行 InvokeHandler 调用处理器的invoke(…)方法

    前面讲到,JDK Proxy动态代理实例的真正的方法调用过程,具体是通过 InvokeHandler 调用处理器完成的。故,这里的DemoClientProxy代理实例,会调用到默认的FeignInvocationHandler 调用处理器实例的invoke(…)方法。

    通过前面 FeignInvocationHandler 调用处理器的详细介绍,大家已经知道,默认的调用处理器 FeignInvocationHandle,内部保持了一个远程调用方法实例和方法处理器的一个Key-Value键值对Map映射。FeignInvocationHandle 在其invoke(…)方法中,会根据Java反射的方法实例,在dispatch 映射对象中,找到对应的 MethodHandler 方法处理器,然后由后者完成实际的HTTP请求和结果的处理。

    所以在第2步中,FeignInvocationHandle 会从自己的 dispatch映射中,找到hello()方法所对应的MethodHandler 方法处理器,然后调用其 invoke(…)方法。

    第3步:执行 MethodHandler 方法处理器的invoke(…)方法

    通过前面关于 MethodHandler 方法处理器的非常详细的组件介绍,大家都知道,feign默认的方法处理器为 SynchronousMethodHandler,其invoke(…)方法主要是通过内部成员feign客户端成员 client,完成远程 URL 请求执行和获取远程结果。

    feign.Client 客户端有多种类型,不同的类型,完成URL请求处理的具体方式不同。

    第4步:通过 feign.Client 客户端成员,完成远程 URL 请求执行和获取远程结果

    如果MethodHandler方法处理器实例中的client客户端,是默认的 feign.Client.Default 实现类性,则使用JDK自带的HttpURLConnnection类,完成远程 URL 请求执行和获取远程结果。

    如果MethodHandler方法处理器实例中的client客户端,是 ApacheHttpClient 客户端实现类性,则使用 Apache httpclient 开源组件,完成远程 URL 请求执行和获取远程结果。

    通过以上四步,应该可以清晰的了解到了 SpringCloud中的 feign 远程调用执行流程和运行机制。

    实际上,为了简明扼要的介绍清楚默认的调用流程,上面的流程,实际上省略了一个步骤:第3步,实际可以分为两小步。为啥呢? SynchronousMethodHandler 并不是直接完成远程URL的请求,而是通过负载均衡机制,定位到合适的远程server 服务器,然后再完成真正的远程URL请求。换句话说,SynchronousMethodHandler实例的client成员,其实际不是feign.Client.Default类型,而是 LoadBalancerFeignClient 客户端负载均衡类型。 因此,上面的第3步,如果进一步细分话,大致如下:(1)首先通过 SynchronousMethodHandler 内部的client实例,实质为负责客户端负载均衡 LoadBalancerFeignClient 实例,首先查找到远程的 server 服务端;(2) 然后再由LoadBalancerFeignClient 实例内部包装的feign.Client.Default 内部类实例,去请求server端服务器,完成URL请求处理。

    最后,说明下,默认的与 FeignInvocationHandler 相关的远程调用执行流程,在运行机制以及调用性能上,满足不了生产环境的要求,为啥呢? 大致原因有以下两点:

    (1) 没有远程调用过程中的熔断监测和恢复机制;

    (2) 也没有用到高性能的HTTP连接池技术。

    接下来,将为大家介绍一下用到熔断监测和恢复机制 Hystrix 技术的远程调用执行流程,该流程中,远程接口的JDK Proxy动态代理实例所使用的调用处理器,叫做 HystrixInvocationHandler 调用处理器。

  6.  

 

 


http://chatgpt.dhexx.cn/article/S8f6nGuN.shtml

相关文章

Feign的工作原理

Feign的工作原理 Feign是一个伪Java Http 客户端&#xff0c;Feign 不做任何的请求处理。Feign 通过处理注解生成Request模板&#xff0c;从而简化了Http API 的开发。开发人员可以使用注解的方式定制Request API模板。 在发送Http Request请求之前&#xff0c;Feign通过处理…

Linux命令——tar与gzip详解:文件的打包压缩与解压缩解打包

Linux系统中&#xff0c;最常用的打包命令就是tar了&#xff0c;不仅如此&#xff0c;tar命令还可以解打包解压缩&#xff0c;十分方便。如果单纯想压缩文件&#xff0c;就需要我们的gzip命令了。 使用tar打包归档的包叫做tar包&#xff0c;以.tar结尾 使用gzip压缩的文件&…

Linux 下使用 tar 命令打包指定目录下的所有文件,不包括目录

一&#xff0c;问题描述 无论是 Linux 系统&#xff0c;还是 macOS 系统&#xff0c;我们都可以使用 tar 命令进行文件的压缩打包。命令格式如下&#xff1a; # tar cvf xxxx.tar 要压缩的文件或目录名称但如果要压缩的目录层级比较多时&#xff0c;比如&#xff1a; # tar cvf…

linux tar (打包、压缩、解压)命令

打包程序&#xff1a;tar c: 创建文档t&#xff1a; 列出存档内容x&#xff1a;提取存档f&#xff1a; filename 要操作的文档名v&#xff1a;详细信息 一&#xff1a;打包 打包&#xff1a;是指把文件整合在一起&#xff0c;不压缩 1.将文件打包&#xff1a;tar cf a.ta…

(21)tar打包命令详解

Linux 系统中,最常用的归档(打包)命令就是 tar,该命令可以将许多文件一起保存到一个单独的磁盘中进行归档。不仅如此,该命令还可以从归档文件中还原所需文件,也就是打包的反过程,称为解打包。1.tar命令做打包操作  当 tar 命令用于打包操作时,该命令的基本格式为: …

vector中删除某个指定元素

class Solution { public:int removeElement(vector<int>& v, int val) {for (auto it v.begin(); it ! v.end(); it) {if (*it val) { // 条件语句v.erase(it); // 移除他it--; // 让该迭代器指向前一个}}return v.size();} };

vector删除指定元素

C vector中实际删除元素使用的是容器vecrot中std::vector::erase()方法。 C 中std::remove()并不删除元素&#xff0c;因为容器的size()没有变化&#xff0c;只是元素的替换。 1.std::vector::erase() 函数原型&#xff1a;iterator erase (iterator position);  //删除指定…

C++中vector中删除/添加指定位置处的元素

1、函数介绍 C中vector容器可以删除/添加制定位置处的元素&#xff0c;分别使用erase()与insert()函数。其中函数内需要两个参数&#xff0c;第一个为指定删除/添加的位置&#xff0c;第二个元素为删除/添加的元素值。 iterator insert(const_iterator _Where, _Ty&&…

C/C++ vector 删除指定元素

C vector 删除符合条件的元素C vector中实际删除元素使用的是容器vecrot中std::vector::erase()方法。C 中std::remove()并不删除元素&#xff0c;因为容器的size()没有变化&#xff0c;只是元素的替换。1.std::vector::erase()  函数原型&#xff1a;iterator erase (iterat…

【c++】vector中删除元素

目录 1.删除指定范围的元素2.删除指定大小的元素3.C20 std::erase, std::erase_if (std::vector)注意点 1.删除指定范围的元素 vector删除元素之pop_back(),erase(),remove() 向量容器vector的成员函数pop_back()可以删除最后一个元素. 而函数erase()可以删除由一个iterator指…

光纤光学原理相关基础知识点

记&#xff1a;研究生导师的方向是光纤光学和机器学习交叉的&#xff0c;导师给推荐了本书&#xff0c;书里面的理论和推导公式作为小白的我真的是不太行&#xff0c;后来在中国大学mooc上找了视频课跟着学习&#xff0c;顺便做下笔记&#xff0c;为日后使用&#xff0c;因此会…

机器人学重点知识点总结

机器人学重点知识点总结 坐标转换与机械臂运动学雅克比矩阵机械臂逆向动力学&#xff08;牛顿欧拉递推&#xff09;机械臂正向动力学运动轨迹生成动力学轨迹跟踪控制 这篇博客主要用来记录一下现代机器人学里面比较基础也比较重要的一些知识点&#xff0c;所有内容均仅仅记录是…

大学物理(下)知识点总结

大学物理&#xff08;下&#xff09;知识点总结&#xff08;持续更新&#xff09; 文章目录 大学物理&#xff08;下&#xff09;知识点总结&#xff08;持续更新&#xff09;静电场知识点总结习题精选 磁场知识点总结习题精选 期中复习总结电磁场知识点总结习题精选 狭义相对论…

Lumerical官方案例、FDTD时域有限差分法仿真学习(二)——宽带光栅耦合器(Broadband grating coupler (2D))

这个 2D FDTD 示例展示了如何获得光栅耦合器的宽带特性&#xff0c;并将结果与实验数据进行比较。 此外&#xff0c;该应用示例演示了多频波束计算的正确使用和优势&#xff0c;并将结果与标准单频波束计算进行了比较。 要更好地了解单频和多频波束计算之间的差异&#xff0c;请…

三维计算机视觉(四)--关键点

关键点又称为感兴趣的点&#xff0c;是低层次视觉通往高层次视觉的捷径&#xff0c;抑或是高层次感知对低层次处理手段的妥协。 RangeImage 1.关键点&#xff0c;线&#xff0c;面 关键点特征点&#xff1b; 关键线边缘&#xff1b; 关键面foreground&#xff1b; 上述三个概…

信号完整性基础04:串扰(1)

说在开头&#xff1a;关于x射线&#xff08;2&#xff09; 1895年11月8日&#xff0c;德国维尔茨堡大学的一间实验室里&#xff0c;校长伦琴正在做克鲁克斯管实验&#xff0c;当时房间没开灯&#xff0c;屋子里一片漆黑&#xff0c;放电管用黑纸包得很严实&#xff0c;他突然发…

基于地平面的单目视觉里程计绝对尺度估计

点击上方“3D视觉工坊”&#xff0c;选择“星标” 干货第一时间送达 ●论文摘要 对于基于单目相机的系统来说&#xff0c;从单目相机中恢复绝对度量尺度是一个具有挑战性的问题。利用有限的已知条件&#xff0c;提出了多种尺度估计方法&#xff0c;如根据相机的高度、物体大小等…

comsol 学习笔记【基础知识,磁场与结构场耦合为主】

感悟 随时补充学习中的感悟&#xff0c;放在开头是为了后来者在学习过程中有所参考。 掌握基本操作&#xff0c;学会寻找资料先看基础视频&#xff0c;然后找专题视频&#xff0c;再去学习案例&#xff08;以官方视频优先、案例配有相关的文件&#xff09;学习案例会涉及到其…

硬件工程师面试基础知识点

目录 一、晶振电路 二、LDO选型 1.LDO工作原理 2.输入电压 3.效率 4.功耗 5.电源抑制比PSRR 6.线性调整率 Line Regulation 7.负载调节率 (Load Regulation) 8.静态电流 9.噪声 10.输出电容器 11.反向泄漏保护 12.RF、音频的应用 三、DC-DC 1.降压转换器-Buck…

PCL—关键点检测(NARF)低层次点云处理

博客转载自&#xff1a;http://www.cnblogs.com/ironstark/p/5051533.html 关键点检测本质上来说&#xff0c;并不是一个独立的部分&#xff0c;它往往和特征描述联系在一起&#xff0c;再将特征描述和识别、寻物联系在一起。关键点检测可以说是通往高层次视觉的重要基础。但本…