微服务之远程调用

常见的远程调用方式

RPC:Remote Produce Call远程过程调用,类似的还有 。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo (12不再维护、17年维护权交给apache),都是RPC的典型代表

Http:http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。现在热门的Rest风格,就可以通过http协议来实现。

跨域调用

跨域特指前端页面调用后端api,即前端页面在一个服务器,后端api在另外一个服务器,是浏览器安全保护行为,与后端没有关系。一般在前后端分离的项目中要解决跨域问题。解决跨域一般有以下几种方式:

(1)ajax+jsonp

(2)proxytable

(3)@CrossOrigin

(4)nginx代理

(5)response.setHeader(“Access-Control-Allow-Origin”, “*”);

远程调用

远程调用技术特指后端不同服务器之间的调用,例如在A服务的api中调用B服务的api。以下的技术都可以完成A服务调用B服务:

(1)dubbo+zookeeper

(2)springcloud中的eureka+feign

(3)httpclient/okhttp3

(4)spring中的RestTemplate

(5)webservice

1、HttpClient

1) HttpClient介绍

HttpClient是一个基于Java的HTTP客户端库,主要用于提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包。以下是关于HttpClient的详细介绍:

1.项目背景:
        - HttpClient是Apache Jakarta Common下的子项目。
        - 它支持HTTP协议最新的版本和建议。
2.主要功能:
        - 发送HTTP请求:HttpClient可以发送GET、POST、PUT、DELETE、HEAD等HTTP请求。
        - 支持HTTPS:HttpClient可以与HTTPS协议一起使用,可以识别和验证服务器证书,并使用加密算法保护请求和响应的数据。
        - 连接管理:HttpClient可以管理多个连接,实现更高效的使用。
        - 请求和响应拦截器:支持添加请求和响应拦截器,可以对请求和响应进行自定义处理(如添加请求头、解析响应内容等)。
        - 连接和请求池:通过连接池和请求池来最大化利用连接和资源,实现更快速和更可靠的HTTP通信。
        - 自定义连接设置:支持自定义连接设置,如设置连接超时时间、请求超时时间、代理等。
        - 支持重定向:默认支持HTTP重定向,可以设置是否允许重定向以及最大重定向次数。
        - 支持认证:支持基本认证、摘要认证、NTLM认证等。
        - 支持缓存:可以使用本地缓存,减少对服务器的请求次数,提高性能。
3.使用场景:
        - 需要调用其他系统接口时,尤其是基于HTTP协议的接口,例如微信支付、查看地图、获取短信验证码、获取天气等。
4.核心API:
        - HttpClient:Http客户端对象,使用该类型对象可发起Http请求。
        - HttpClients:构建器,用于获得HttpClient对象。
        - CloseableHttpClient:具体实现类,实现了HttpClient接口。
        - HttpGet、HttpPost等:不同的HTTP请求方式对应的请求类型。

2)HttpClient使用

使用步骤(以GET请求为例):

    • 引入Maven坐标(依赖项)。
    • 创建HttpClient对象。
    • 创建HttpGet请求对象,并设置目标URL。
    • (可选)添加请求头。
    • 执行请求并获取响应。
    • 提取响应状态码和响应实体内容

引入依赖

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

HttpClient工具类

package com.example.producer.utils;

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpClientUtil {

    public static String doGet(String url, Map<String, String> param) {

        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String doGet(String url) {
        return doGet(url, null);
    }

    public static String doPost(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return resultString;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }

    public static String doPostJson(String url, String json) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return resultString;
    }
}

代码实现

//使用httpclient
@RequestMapping("/orderToMember1")
public String orderToMember1() {
    // 使用httpclient调用接口
    return "订单调用会员服务返回结果" + com.example.producer.utils.HttpClientUtil.doGet("http://127.0.0.1:8082/getMember", null);
}

2、RestTemplate

1)RestTemplate介绍

RestTemplate是Spring Framework提供的一个用于发送HTTP请求的客户端工具类。它简化了在Java应用程序中进行HTTP通信的过程,封装了底层的HTTP连接和请求/响应处理逻辑。

RestTemplate的主要特点和功能包括:

支持多种HTTP方法:RestTemplate支持常见的HTTP方法,如GET、POST、PUT、DELETE等,可以根据需要选择合适的方法来发送请求。

提供丰富的请求和响应处理方法:RestTemplate提供了多种方法来处理请求和响应,如添加请求头、设置请求参数、发送请求、获取响应等。开发者可以根据需要选择合适的方法来处理HTTP请求和响应。

支持请求和响应的序列化和反序列化:RestTemplate可以将请求和响应的数据进行序列化和反序列化,支持多种数据格式,如JSON、XML等。开发者可以根据需要选择合适的序列化和反序列化方式。

支持错误处理和异常处理:RestTemplate可以处理HTTP请求过程中的错误和异常,如连接超时、请求失败等。开发者可以根据需要进行错误处理和异常处理。

可扩展性和定制化:RestTemplate提供了一些扩展点和配置选项,可以进行定制化配置。开发者可以根据需要进行扩展和定制,以满足特定的业务需求。

常用方法:

2)RestTemplate使用

声明restTemplateBean方式一

@Bean
public RestTemplate getRestTemplate(){
    return new RestTemplate();
}

声明restTemplateBean方式二

@Bean
public RestTemplate getRestTemplate(RestTemplateBuilder builder){
    return builder.build();
}

远程调用实现

    @Autowired
    private RestTemplate restTemplate;

   
    @RequestMapping("/getId")
    public String consumerRest(){
        String url = "http://localhost:8082/getMember";
        String consumer = restTemplate.getForObject(url,String.class);
        return "restTemplate consumer如下=http://localhost:8082/getMember" + consumer;
    }

3、WebClient

1)WebClient介绍

WebClient是一个用于执行HTTP请求的客户端,具有多种实现和用途。以下是关于WebClient的详细解释:
1.定义与原理:
        - WebClient是一种非阻塞、响应式客户端,主要用于执行HTTP请求。它可以在处理高并发HTTP请求时,以少量的线程数提供快速响应。
        - 与传统的RestTemplate相比,WebClient是异步执行的,不会阻塞代码,直到HTTP请求返回响应。这使得WebClient在处理大量并发请求时更加高效。
        - WebClient支持同步、异步和流式场景,提供了RestTemplate的替代方案。
2.功能特点:
        - 非阻塞I/O:WebClient使用非阻塞I/O模型,使得在等待HTTP响应时不会阻塞线程。
        - 反应流背压:WebClient支持反应流背压,这是一种控制数据流速的机制,可以防止数据生产者过快地发送数据,导致数据消费者处理不过来。
        - 高并发性:由于WebClient的非阻塞特性,它在硬件资源较少的情况下也能支持高并发请求。
        - 函数式风格与流畅API:WebClient提供了函数式编程风格和流畅的API,使得代码更加简洁和易于阅读。
        - 支持多种场景:WebClient不仅支持传统的HTTP请求,还支持流式传输、WebSocket等场景。

2)WebClient使用

添加webflux依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

编写配置类


import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
 
 
@Component
public class WebClientConfig {
 
    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

编写测试类

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
 
import javax.annotation.Resource;
 
 
@RestController
@RequestMapping("/client")
public class TestClientController {
 
    @Resource
    private WebClient.Builder webClientBuilder;
 
    @GetMapping("/echo/{str}")
    public Mono<String> echo(@PathVariable("str") String str) {
        return webClientBuilder.build()     // 创建WebClient实例
                .get()                      // 请求方式
                .uri("http://service-provider/echo/{1}", str) // 请求url
                .retrieve()                 // 获取响应结果
                .bodyToMono(String.class);  // 将结果转换为指定类型
    }
 
}

3)API详解

请求方式

响应类型

4、OpenFeign

1)OpenFeign介绍

OpenFeign是一个声明式的Web服务客户端,它是Spring Cloud中的一个组件,用于简化和优化微服务架构中的服务间调用。OpenFeign基于Netflix的Feign库进行了扩展和增强。

OpenFeign的主要特点和功能包括:

声明式的API定义:通过使用注解,开发者可以定义和描述服务间的API接口,包括请求方法、路径、参数、请求头等信息。这样可以使得服务间的调用代码更加简洁和易于维护。

自动化的服务发现和负载均衡:OpenFeign集成了服务注册中心,可以自动发现和调用其他微服务。它还支持负载均衡,可以根据配置的负载均衡策略选择合适的服务实例进行调用。

内置的请求和响应拦截器:OpenFeign提供了一些内置的拦截器,可以在请求和响应的不同阶段进行拦截和处理。开发者可以自定义拦截器来实现日志记录、错误处理等功能。

支持多种编码器和解码器:OpenFeign支持多种编码器和解码器,可以处理不同的数据格式,如JSON、XML等。开发者可以根据需要选择合适的编码器和解码器。

整合了Hystrix和Ribbon:OpenFeign与Hystrix和Ribbon等其他Spring Cloud组件集成,可以实现服务的容错和熔断机制,提高系统的可靠性和稳定性。

总之,OpenFeign简化了微服务架构中的服务间调用,提供了一种简洁、声明式的方式来定义和调用服务API。它与Spring Cloud的其他组件集成良好,是构建和管理微服务架构的重要工具之一。

2)OpenFeign使用

① 添加 OpenFeign依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>

② 创建Feign客户端接口

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "producer")   //标记的接口用于定义远程服务的调用
public interface RemoteClient {

    @GetMapping("/getMember")
    String helloNacos();
}

③ 使用Feign客户端

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
@EnableFeignClients
@EnableDiscoveryClient
public class NacosFeignApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosFeignApplication.class, args);
    }

    @Autowired
    private RemoteClient remoteClient;

    @GetMapping("/feign")
    public String test() {
        return remoteClient.helloNacos();
    }
}

④ 注册配置及controller

spring:
  application:
    name: producer
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
server:
  port: 8083

=========================================================================
@RestController
@Slf4j
public class ProducerController {
    @Value("${server.port}")
    private String port;

    @RequestMapping("/getMember")
    public String getMember() {
        return "The port of producer is "+port;
    }
}

5、Feign

1)Feign介绍

1.定义:
        - Feign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加容易。
        - Feign的设计目标是让Web服务调用变得更加简单,无论是在本地还是在远程。
2.特点:
        - 声明式API定义:通过简单的注解,开发者可以定义需要调用的远程服务的API接口。
        - 集成了负载均衡:Feign默认集成了Ribbon负载均衡器,使得服务调用更加健壮和可靠。
        - 自动化的服务发现:Feign通过服务名自动进行服务发现,无需手动指定远程服务的IP地址和端口。
3.与其他技术的关系:
        - Feign在RestTemplate和Ribbon的基础上进一步封装,使用RestTemplate实现HTTP调用,使用Ribbon实现负载均衡

2)Feign调用步骤

程序启动时,扫描所有的@FeignClient注解

当接口方法被调用时,通过JDK代理来生成RequestTemplate模板

根据RequestTemplate模板生成Http请求的Request对象

Request对象交给Client去处理,其中Client的网络请求框架可以是HttpURLConnection、HttpClient、OKHttp

最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用

6、比较

1)HttpClient、RestTemplate、WebClient的比较

        ①HttpClient

    • 来源:HttpClient是Apache基金会下的一个项目,提供了丰富的HTTP客户端功能。
    • 功能:
      • 支持HTTP/1.1和HTTP/2协议。
      • 提供了连接池管理,用于复用HTTP连接,提高性能。
      • 支持异步和同步请求。
      • 提供了详细的请求和响应控制,如自定义请求头、响应拦截等。
    • 使用方式:通常直接通过HttpClient的API来发起请求,需要编写较多的代码来处理请求和响应。
    • 性能:由于支持连接池和HTTP/2的多路复用,HttpClient在处理大量并发请求时具有优秀的性能表现。

        ②RestTemplate

    • 来源:RestTemplate是Spring框架提供的一个HTTP客户端工具,用于简化与RESTful服务的交互。
    • 功能:
      • 提供了统一的模板方法来发送HTTP请求,如GET、POST、PUT、DELETE等。
      • 支持URI模板,方便构建动态URL。
      • 可以通过实现ClientHttpRequestFactory来定制底层HTTP请求的实现,如使用Apache HttpClient、OkHttp等。
      • 提供了消息转换器,用于将请求和响应体转换为Java对象。
    • 使用方式:RestTemplate的使用较为简单,通常只需要注入一个RestTemplate实例,然后调用其方法发送请求即可。
    • 性能:RestTemplate的性能取决于底层HTTP请求的实现。默认情况下,它使用Java标准库的HttpURLConnection,性能一般。但可以通过配置使用更高效的HTTP客户端库来提升性能。

        ③WebClient

    • 来源:WebClient是Spring WebFlux的一部分,用于构建非阻塞的、响应式的Web客户端。
    • 功能:
      • 基于Reactor响应式编程模型,支持非阻塞的HTTP请求。
      • 提供了丰富的操作符来组合和转换请求和响应流。
      • 支持WebSocket和服务器发送的事件(SSE)。
      • 与Spring WebFlux的其他组件(如Router、Filters等)无缝集成。
    • 使用方式:WebClient的使用方式与传统的HTTP客户端有所不同,它基于响应式编程模型,通过链式调用的方式来构建请求和处理响应。
    • 性能:WebClient在处理大量并发请求时具有优秀的性能表现,因为它基于非阻塞的IO模型,能够充分利用系统资源。同时,它也支持HTTP/2协议,具有更高效的多路复用能力。

总结:

  • HttpClient是一个功能强大的HTTP客户端库,提供了丰富的功能和详细的控制选项。它适用于需要高度定制和灵活性的场景。
  • RestTemplate是Spring框架提供的一个HTTP客户端工具,简化了与RESTful服务的交互。它适用于大多数Web应用程序的场景。
  • WebClient是Spring WebFlux的一部分,基于响应式编程模型构建非阻塞的Web客户端。它适用于需要处理大量并发请求和高效利用系统资源的场景。

2)Feign和OpenFeign的比较

1. 定义与背景

  • Feign:Feign是Netflix开发的一个声明式HTTP客户端,它使得编写Web服务客户端变得更加容易。Feign通过注解和动态代理简化了HTTP API的调用。
  • OpenFeign:OpenFeign是Feign的一个开源实现,并且完全兼容Feign的API。OpenFeign提供了更多的功能和扩展性,是Spring Cloud生态系统中用于服务间通信的重要组件。

2. 核心特性

  • Feign:
    • 支持多种HTTP请求类型,包括GET、POST、PUT、DELETE等。
    • 支持多种数据格式,如JSON、XML、文本等。
    • 支持负载均衡和故障转移。
  • OpenFeign:
    • 除了Feign的所有特性外,OpenFeign还支持以下功能:
      • 更多的注解支持,包括@FeignClient、@RequestMapping、@GetMapping、@PostMapping等。
      • 更多的配置选项,如超时、重试、熔断器等。
      • 更多的扩展,如日志记录、监控、安全等。

3. 实现方式

  • Feign:使用Java动态代理来创建HTTP客户端,根据注解自动生成HTTP请求。
  • OpenFeign:使用Java SPI(Service Provider Interface)来创建HTTP客户端,允许用户自定义HTTP客户端的实现。

4. 适用场景

  • Feign:适用于需要简单、强大的声明式HTTP请求库的场景。
  • OpenFeign:适用于需要更强大、更灵活的声明式HTTP请求库的场景,需要自定义HTTP客户端、使用更多注解、配置更多选项或扩展更多功能。

5. 集成与扩展

  • Feign:虽然功能强大,但扩展性相对有限。
  • OpenFeign:作为Spring Cloud的一部分,与Spring Cloud的其他组件(如Eureka、Ribbon等)集成得更好,并且提供了丰富的扩展机制。

6. 性能优化

  • Feign:性能优化主要依赖于底层HTTP客户端的选择和配置。
  • OpenFeign:除了底层HTTP客户端的选择和配置外,OpenFeign还提供了更多的配置选项和扩展机制来优化性能,如连接池、超时设置等。

总结:

Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务

OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

7、常用注解

① @EnableFeignClients

  • 作用:启用Feign客户端。Feign是一个声明式的Web Service客户端,它使得编写Web Service客户端变得更加容易。使用Feign,你可以创建一个接口并注解它,Feign将为你生成实现,负责HTTP请求的发送和接收。
  • 使用场景:在Spring Boot应用的主类上添加此注解,以启用Feign客户端的功能。

② @EnableDiscoveryClient

  • 作用:启用服务发现功能。在微服务架构中,服务发现是一个重要的组件,它允许服务在运行时动态地查找其他服务的位置。
  • 使用场景:通常在Spring Boot应用的主类上添加此注解,如果你正在使用Eureka、Consul、Zookeeper等作为服务发现组件。

③ @FeignClient

  • 作用:定义Feign客户端。通过此注解,你可以指定一个服务ID(通常在服务注册中心中注册的服务名),Feign将为你创建一个客户端,用于与该服务进行通信。
  • 使用场景:在接口上添加此注解,定义Feign客户端。
  • 示例:
@FeignClient(name = "my-service")  
public interface MyServiceClient {  
    // 定义方法,用于调用远程服务的API  
}

④ @RefreshScope

  • 作用:使一个Bean具有动态刷新的能力。当外部配置源(如Spring Cloud Config Server)发生变化时,带有此注解的Bean将被重新创建,从而应用新的配置。
  • 使用场景:当你想要让Bean能够动态地感知并应用配置变化时,可以使用此注解。例如,当配置中心的数据库连接信息发生变化时,带有此注解的数据库连接池Bean将被重新创建,从而使用新的数据库连接信息。或者,直接在Feign客户端接口上使用此注解,以便在配置中心的配置变化时,Feign客户端能够使用新的配置(如新的服务地址)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/705716.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

A+B依旧可以卷!多尺度特征融合+注意力机制,新SOTA准确率高达99%

在处理复杂实际问题时&#xff0c;我们可以结合多尺度特征融合和注意力机制&#xff0c;让模型不仅能从多个尺度上捕获丰富的特征信息&#xff0c;还可以专注于输入中的关键部分&#xff0c;来提高模型的泛化能力和性能。 具体到图像处理领域&#xff0c;这种方法就是允许模型…

风控中的文本相似方法之余弦定理

一、 余弦相似概述 余弦相似性通过测量两个向量的夹角的余弦值来度量它们之间的相似性。0度角的余弦值是1&#xff0c;而其他任何角度的余弦值都不大于1&#xff1b;并且其最小值是-1。 从而两个向量之间的角度的余弦值确定两个向量是否大致指向相同的方向。结果是与向量的长…

重新安装TortoiseGit后提示权限错误问题解决

今天在Windows11系统中下载安装使用TortoiseGit可视化Git工具&#xff0c;进行代码提交管理。 由于电脑之前是一位开发人员在使用&#xff0c;所以曾经安装使用过这个工具。 重新安装好软件后&#xff0c;在coding网站中复制代码路径后&#xff0c;在本地目录通过鼠标右键选择…

WPF/C#:异常处理

什么是异常&#xff1f; 在C#中&#xff0c;异常是在程序执行过程中发生的特殊情况&#xff0c;例如尝试除以零、访问不存在的文件、网络连接中断等。这些情况会中断程序的正常流程。 当C#程序中发生这种特殊情况时&#xff0c;会创建一个异常对象并将其抛出。这个异常对象包…

Go微服务框架Kratos中makefile命令的使用方法及报错处理

运用 kratos 微服务框架开发项目时&#xff0c;可以使用提供的 makefile 中的命令自动且快速生产相关代码&#xff0c;提高开发效率。 krotos中makefile文件内容如下&#xff1a; GOHOSTOS:$(shell go env GOHOSTOS) GOPATH:$(shell go env GOPATH) VERSION$(shell git descri…

翻译英文文献工具

翻译英文文献工具 1. zotero1. 安装zotero2. 安装pdf翻译器2.1. 查看zotero版本2.2. 下载对应的pdf翻译器插件版本2.3. 安装插件2.4. 使用插件 2. 小绿鲸英文文献阅读器1. 安装2. 使用 1. zotero 1. 安装zotero 官网&#xff1a; https://www.zotero.org/ 一键next默认安装就…

(四)React组件、useState、组件样式

1. 组件 1.1 组件是什么 概念&#xff1a;一个组件就是用户界面的一部分&#xff0c;它可以有自己的逻辑和外观&#xff0c;组件之间可以相互嵌套&#xff0c;也可以复用多次。 组件化开发可以让开发者像搭积木一样构建一个完整的庞大应用 1.2 React组件 在React中&#xf…

独具韵味的移动端 UI 风格

独具韵味的移动端 UI 风格

《转载》前苏联的三进制计算机Setun

1、苏联的三进制计算机概述 早在 1956 年&#xff0c;就需要创建一种可在大学和实验室中使用的实用数字计算机模型。为此&#xff0c;需要一种易于学习、可靠、廉价但同时高效、专为大规模使用而设计的小型计算机。 对这种机器的要求&#xff1a;运行速度必须等于每秒数百次操作…

求单源最短路径的新方法

参见&#xff1a;dijkstra 算法为什么高效。 本来不想谈算法&#xff0c;本来只想了一下 dijkstra 算法背后的形而上&#xff0c;但还是归纳出一个仅靠一次广度优先遍历就能获得单源最短路径的新算法&#xff0c;框图里是算法流程&#xff0c;流程下是一个例子&#xff1a; …

Ubuntu Server 20.04挂载磁盘

先查看磁盘信息&#xff1a; sudo fdisk -l然后提供NTFS文件系统支持&#xff1a; sudo mkfs.ntfs /dec/sda -F这个过程非常久… 处理完如上图。&#xff08;ps. 这个 Have a nice day. 好浪漫~&#xff09; 接着挂载磁盘&#xff1a; sudo mount /dev/sda ~/device设置开机…

系统架构设计师 - 操作系统(2)

操作系统 操作系统&#xff08;5-6分&#xff09;文件管理绝对路径与相对路径 ★索引文件 ★★★位示图 ★ 存储管理段页式存储 ★★★页式存储段式存储段页式存储&#xff08;了解&#xff09; 页面置换算法 ★ 微内核操作系统嵌入式操作系统 ★★★ 大家好呀&#xff01;我是…

第五十一天 | 1143.最长公共子序列

题目&#xff1a;1143.最长公共子序列718.最长重复子数组的区别是&#xff0c;子序列不要求连续&#xff0c;子数组要求连续。这一差异体现在dp数组含义和递推公式中&#xff0c;本题是子序列&#xff0c;那就要考虑上nums1[i - 1] ! nums2[j - 1]的情况。 本道题与 1.dp数组…

vue 应用测试(一) --- 介绍

vue 应用测试&#xff08;一&#xff09; ---介绍 前端测试简介组件测试Jest 测试框架简介其他测试框架 第一个测试避免误报如何组织测试代码 组件挂载Vue2 组件挂载的方式Vue3 的挂载方式vue-test-utils挂载选项 如何调试测试用例参考小结 前端测试简介 软件测试&#xff1a;…

【每日一练 】day2

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; &#x1f388;丠丠64-CSDN博客&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起…

企业多云策略的优势与实施指南

企业在选择云服务提供商时&#xff0c;常见的选项包括亚马逊AWS、微软Azure、谷歌云GCP、阿里云、腾讯云和华为云。为了避免过度依赖单一供应商&#xff0c;许多企业选择采用多云策略&#xff0c;这样可以充分利用不同云服务的优势&#xff0c;同时避免重复工作和其他额外的工作…

大模型应用开发课程上新!

在人工智能快速发展的今天&#xff0c;大模型应用已逐渐渗透到各个行业&#xff0c;对我们的工作和生活产生了深远的影响。越来越多的企业和开发者渴望深入探索大模型落地应用&#xff0c;然而却缺少高质量且专业的培训课程及学习途径。 为满足企业和开发者在实际场景中使用大…

ROS——自定义话题消息和使用方法

定义Person话题 定义Person发布者 /*** 该例程将发布/person_info话题&#xff0c;自定义消息类型&#xff1a; test_topic::Person*/#include <ros/ros.h> #include <test_topic/Person.h> //包含的头文件&#xff0c;ros相关的头文件&#xff0c;及自定义头文件…

单点登录分析介绍

文章目录 1、单点登录解决方案1.1、后端保存登录状态1.2、token模式 2、user服务-登录接口2.1、UserController2.2、UserInfoServiceImpl2.3、载荷2.4、响应2.5、Redis Desktop Manager 1、单点登录解决方案 多个系统只有一个登录服务 1.1、后端保存登录状态 1.2、token模式 …

Excel根据身份证号提取信息

概览 本篇文章主要对根据身份证号码提取出生年月日、年龄、性别、退休年龄这三项进行讲解。 一. 提取出生年月日 公式&#xff1a;TEXT(MID(B2,7,8),“0000-00-00”) MID(B2,7,8)&#xff1a;表示从单元格 B2 中的字符串&#xff08;这里是身份证号&#xff09;&#xff0c…