服务调用方式

RPC和HTTP

无论是微服务还是SOA,都面临着服务间的远程调用。那么服务间的远程调用方式有哪些呢?

常见的远程调用方式有以下2种:

  • 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

搭建项目

创建project

微服务怎么优先调用本地启动的服务 微服务调用方式_dubbo

在project(工程、项目)下点击创建module(模块)

微服务怎么优先调用本地启动的服务 微服务调用方式_dubbo_02


选择好maven、选择好父包

微服务怎么优先调用本地启动的服务 微服务调用方式_微服务_03

创建模块

微服务怎么优先调用本地启动的服务 微服务调用方式_微服务_04

在父类模块中POM中引入WEB模块

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.woniu</groupId>
    <artifactId>moon-cloud-knife</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>moon-app-credit</module>
        <module>moon-app-knife</module>
        <module>moon-service-credit</module>
        <module>moon-service-login</module>
        <module>moon-service-order</module>
        <module>moon-service-product</module>
        <module>moon-service-gateway</module>
        <module>moon-common</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <spring.cloud.alibaba.version>2.2.5.RELEASE</spring.cloud.alibaba.version>
        <spring.boot.version>2.3.11.RELEASE</spring.boot.version>
        <spring.cloud.version>Hoxton.SR8</spring.cloud.version>
    </properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.12</version>
    </dependency>

    <!--        JSON-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
<dependencies>
    <!--Spring Cloud alibaba的版本管理, 通过dependency完成继承-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>${spring.cloud.alibaba.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring.cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring.boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.32</version>
    </dependency>


    <!--         fastjson-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.79</version>
    </dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>3.0.2</version>
        <configuration>
            <excludes>
                <exclude>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                </exclude>
            </excludes>
        </configuration>
    </plugin>
</plugins>
</build>

</project>

增加配置文件application.yml

微服务怎么优先调用本地启动的服务 微服务调用方式_微服务_05

moon-app-credit

application.yml

server:
  port: 9000

CarController

@RestController
public class CarController{

   @Value("${server.port}")
    private String port;

    @RequestMapping(value = "/app/credit/{id}")
    public String provider(@PathVariable String id){
        return "credit id = " + id + " port = " + port;
    }

}

运行结果

微服务怎么优先调用本地启动的服务 微服务调用方式_微服务_06

moon-service-product

application.yml

server:
  port: 8030

SkuController

@RestController
public class SkuController{

   @RequestMapping(value = "/TestSku/{id}")
    public String TestSku(@PathVariable String id){
        return "TestSku id="+id;
    }
}

运行结果

微服务怎么优先调用本地启动的服务 微服务调用方式_dubbo_07

HttpClient和OkHttp3性能比

  • client连接为单例:
    单例模式下,HttpClient的响应速度要更快一些,单位为毫秒,性能差异相差不大
  • 非单例模式下,OkHttp的性能更好,HttpClient创建连接比较耗时,因为多数情况下这些资源都会写成单例模式。
  • HttpClient+okhttp+URLConnection
    我新建一个test模块

HttpClien

<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
@RestController
public class TestController {

    /**
     * @title consumerHttp
     *
     * @param: id
     * @updateTime 2022/11/9 15:09
     * @return: java.lang.String
     * @throws
     * @Description: HttpClient调用方式
     */
    @RequestMapping(value = "/consumerHttp/{id}")
    public String consumerHttp(@PathVariable String id){
        String consumer = null;
        String url = "http://localhost:8030/TestSku/"+id;

        HttpClient httpClient = new HttpClient();
        GetMethod getMethod = new GetMethod(url);
        try {
            httpClient.executeMethod(getMethod);
            byte[] body = getMethod.getResponseBody();
            consumer = new String(body, "UTF-8");
        } catch (IOException e) {
            return "HttpClient consumer exception";
        }
        return "HttpClient consumer :http://localhost:8030/TestSku/id="+id+"~~~~" + consumer;
    }
    @RequestMapping("/test1008611")
    public String a(){
        return "lps";
    }

}

运行结果:

微服务怎么优先调用本地启动的服务 微服务调用方式_dubbo_08

okhttp3

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.2</version>
</dependency>
/**
     * @title consumerok
     *
     * @param: id
     * @updateTime 2023/05/20 10:25
     * @return: java.lang.String
     * @throws
     * @Description: OkHttpClient调用方式
     */
    @RequestMapping(value = "/consumerok/{id}")
    public String consumerok(@PathVariable String id){
        String consumer = null;
        String url = "http://localhost:8030/TestSku/"+id;

        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        Response response = null;
        try {
            response = okHttpClient.newCall(request).execute();
            consumer = response.body().string();
        } catch (IOException e) {
            return "OkHttpClient consumer exception";
        }
        return "OkHttpClient调用方式,HttpClient consumer :http://localhost:8030/TestSku/id="+id+"~~~~" + consumer;
    }

运行结果:

微服务怎么优先调用本地启动的服务 微服务调用方式_dubbo_09

Spring的RestTemplate

RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。RestTemplate 继承InterceptingHttpAccessor 并且实现了 RestOperations 接口,其中 RestOperations 接口定义了基本的 RESTful 操作,这些操作在 RestTemplate 中都得到了实现

常用方法:

HTTP Method

常用方法

描述

GET

getForObject

发起 GET 请求响应对象

GET

getForEntity

发起 GET 请求响应结果、包含响应对象、请求头、状态码等 HTTP 协议详细内容

POST

postForObject

发起 POST 请求响应对象

POST

postForEntity

发起 POST 请求响应结果、包含响应对象、请求头、状态码等 HTTP 协议详细内容

DELETE

delete

发起 HTTP 的 DELETE 方法请求

PUT

put

发起 HTTP 的 PUT 方法请求

声明restTemplateBean方式一

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

声明restTemplateBean方式二

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

restTemplate远程调用

@Autowired
    private RestTemplate restTemplate;

    /**
     * @title consumerRest
     *
     * @param: id
     * @updateTime 2022/11/9 15:28
     * @return: java.lang.String
     * @throws
     * @Description: restTemplate调用方式
     */
     @RequestMapping(value = "/consumerRest/{id}")
    public String consumerRest(@PathVariable String id){
        String url = "http://localhost:8030/TestSku/"+id;
        String consumer = restTemplate.getForObject(url,String.class);
        return "restTemplate consumer如下=http://localhost:8030/TestSku/id="+id+"~~~~" + consumer;
    }

运行结果:

微服务怎么优先调用本地启动的服务 微服务调用方式_微服务怎么优先调用本地启动的服务_10


没有设置负载均衡的话,启动类别加负载均衡的注解,@LoadBalanced,因为没有更改获取资源的路径,所以会报错

java.lang.IllegalStateException: No instances available for localhost

SpringCloud

微服务是一种架构方式,最终肯定需要技术架构去实施。

微服务的实现方式很多,目前Spring Cloud比较流行。为什么?

  • 后台硬:作为Spring家族的一员,有整个Spring全家桶靠山,背景十分强大。
  • 技术强:Spring作为Java领域的前辈,可以说是功力深厚,有强力的技术团队支撑。
  • 群众基础好:大多数程序员的成长都伴随着Spring框架,现在有几家公司开发不用Spring?SpringCloud与Spring的各个框架无缝整合,对大家来说一切都是熟悉的配方,熟悉的味道。
  • 使用方便:相信大家都体会到了SpringBoot给我们开发带来的便利,而SpringCloud完全支持SpringBoot的开发,用很少的配置就能完成微服务框架的搭建。

微服务怎么优先调用本地启动的服务 微服务调用方式_微服务怎么优先调用本地启动的服务_11

简介

SpringCloud是Spring旗下的项目之一:

Spring最擅长的就是集成,把世界上最好的框架拿过来,集成到自己的项目中。

SpringCloud也是一样,它将现在非常流行的一些技术整合到一起,实现了诸如:配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等等功能。其主要涉及的组件包括:

  • Eureka:服务治理组件,包含服务注册中心,服务注册与发现机制的实现。(服务治理,服务注册/发现)
  • Zuul(gateway):网关组件,提供智能路由,访问过滤功能
  • Ribbon:客户端负载均衡的服务调用组件(客户端负载)
  • Feign(open feign):服务调用,给予Ribbon和Hystrix的声明式服务调用组件 (声明式服务调用)
  • Hystrix:容错管理组件,实现断路器模式,帮助服务依赖中出现的延迟和为故障提供强大的容错能力。(熔断、断路器,容错)

版本

因为Spring Cloud不同其他独立项目,它拥有很多子项目的大项目。所以它的版本是版本名+版本号 (如Angel.SR6)。

版本名:是伦敦的地铁名

版本号:SR(Service Releases)是固定的 ,大概意思是稳定版本。后面会有一个递增的数字。

所以 Edgware.SR3就是Edgware的第3个Release版本。

微服务怎么优先调用本地启动的服务 微服务调用方式_微服务_12