ServiceComb 课程

一、 ServiceComb 概述

背景介绍

ServiceComb 作为 Apache 开源组织下的一款微服务框架,其前身为华为云的 微服务引擎 CSE (Cloud Service Engine) 云服务。

它意味着国内一款微服务框架在华为和 Apache 组织的共同努力下,随着微服务市场的火爆,一定会让越来越多的开发者所喜欢。

首要原则

全球首款进入 Apache 的开源微服务项目,中立、开放、标准、无商业 Lock-in开源与商业代码同源,具备零成本平滑迁移商用的能力,社区长足发展有保障

技术方案

解决方案级,多语言、多通信协议、标准服务契约、事务最终一致性开源开放,拥抱 SpringBoot、 SpringCloud、 ServiceMesh 等主流生态低门槛准入,业务侵入度低,架构松耦合

官方网站介绍

华为将 ServiceComb 贡献给了 Apache 基金组织后,我们就可以通过 Apache 的官方网站提供的资料来学习 ServiceComb,下面是官网地址:

二、 ServiceComb 与 SpringCloud 的比较

我们可以从语言框架,编程模型,通信协议,服务治理,服务访问,分布式事务等方面进行比较,得出结果如下:

领域 功能 SpringCloud ServiceComb
多语言框架 JAVA 微服务框架
多语言框架 非侵入微服务框架 ×
多编程模型 POJO 编程模型 ×
多编程模型 SpringMVC 编程模型
多编程模型 JAX-RS 编程模型 ×
多编程模型 Reactive 响应式编程 ×
多通信协议 Rest
多通信协议 RPC ×
服务治理 负载均衡
服务治理 服务限流
服务治理 服务隔离
服务治理 服务容错
服务治理 服务熔断
服务治理 错误注入 ×
服务治理 服务中心
服务治理 配置中心
服务访问 安全协议
服务访问 安全认证
服务访问 服务契约
分布式事务 务一致性方案 ×

通过上图的对比,我们可以得出结论就是 ServiceComb 在微服务开发上更胜一筹。我们有理由相信 ServiceComb 将会在微服务开发领域成为国人的骄傲。

三、 ServiceComb 的开放性设计思想

1、编程模型和通信模型分离,不同的编程模型可以灵活组合不同的通信模型。应用开发者在开发阶段只关注接口开发,部署阶段灵活切换通信方式;支持 legacy 系统的切换, legacy 系统只需要修改服务发布的配置文件(或者 annotation),而不需要修改代码。

现阶段支持 SpringMVC、 JAX-RS 和透明 RPC 三种开发方式。

2、内建 API-first 支持。通过契约规范化微服务开发,实现跨语言的通信,并支持配套的软件工具链(契约生成代码、代码生成契约等)开发,构建完整的开发生态。

3、定义了常用的微服务运行模型,将微服务从发现到交互过程中的各种容错手段都封装起来。该运行模型支持自定义和扩展。
在这里插入图片描述

四、 ServiceComb 微服务解决方案

在这里插入图片描述

五、 安装 ServiceComb 开发环境

应用开发环境所需安装的工具包括 JDK、 Maven、 Eclipse 和 IDEA 。

六、 服务注册中心 CSE 介绍

服务注册中心基本介绍

现在我们介绍如何在开发者本地进行消费者/提供者应用的开发调试。

开发服务提供者和消费提供者均需要连接到在远程的服务中心,为了本地微服务的开发和调试:

启动本地服务中心

服务中心是微服务框架中的重要组件,用于服务元数据以及服务实例元数据的管理和处理注册、发现。服务中心与微服务提供/消费者的逻辑关系下图所示:
在这里插入图片描述

ServiceComb设计理念图分析

在这里插入图片描述

ServiceComb服务注册中心CSE概述及原理分析

在这里插入图片描述

ServiceComb入门程序配置文件分析

在这里插入图片描述

ServiceComb入门程序及URL分析

在这里插入图片描述

启动本地服务中心

1、下载[服务注册中心可执行文件压缩包]

(http://apache.org/dyn/closer.cgi/incubator/servicecomb/incubator-servicecomb-service-center/1.0.0-m1/apache-servicecomb-incubating-service-center-1.0.0-m1-windows-amd64.tar.gz)

2、解压缩到当前文件夹

3、进入解压缩后的目录,然后双击运行 start-service-center.bat 文件

注意: Window 和 Linux 版本均只支持 64 位系统。 {: .notice–warning}

以 Docker 的方式运行

docker pull servicecomb/service-center
docker run -d -p 30100:30100 servicecomb/service-center:latest

载后的 CSE 服务注册中心,并打开目录结构如下:

在这里插入图片描述
打开 conf/app.conf 文件后,可以找到 CSE 基本配置如下:

服务端配置:

# sever options
###################################################################
# if you want to listen at ipv6 address, then set the httpaddr value like:
# httpaddr = 2400:A480:AAAA:200::159 (global scope)
# httpaddr = fe80::f816:3eff:fe17:c38b%eth0 (link-local scope)
httpaddr = 127.0.0.1
httpport = 30100
read_header_timeout = 60s
read_timeout = 60s
idle_timeout = 60s
write_timeout = 60s
max_header_bytes = 32768 # 32K
max_body_bytes = 2097152 # 2M
enable_pprof = 0

前端配置:

# Frontend Configurations
###################################################################
frontend_host_ip = 127.0.0.1
frontend_host_port = 30103

2、启动本地服务中心后,在服务提供/消费者的 microservice.yaml 文件中配置 ServerCenter 的地址和端口,示例代码:

servicecomb:
  service:
  registry:
  address:  http://127.0.0.1:30100 #服务中心地址及端口

3、开发服务提供/消费者,启动微服务进行本地测试。

通过设置环境信息方便本地调试

通过 microservice.yaml 配置文件来指定

service_description:
  environment: development
ServiceComb开发步骤总结

在这里插入图片描述

七、 使用官方提供的脚手架快速开发 ServiceComb

为了能够使开发者可以快速构建 ServiceComb 应用程序,它同样也为我们提供了一套脚手架,这样能够方便学习者及应用开发者快速入门,同时极大的提高了效率。

1、访问快速开发引导页:http://start.servicecomb.io/,页面如下:
在这里插入图片描述
后面我们就可以填写工程相关内容,最后就可以生成代码了。下载后的工程
在这里插入图片描述
解压工程,导入到 Idea 工具中。

八、 ServiceComb 服务的线程模型与通信协议

ServiceComb 实现了两种网络通道,包括 REST 和 Highway,均支持 TLS 加密传输。其中, REST 网络通道将服务以标准 RESTful 形式发布,调用端兼容直接使用 http client 使用标准 RESTful 形式进行调用。

线程模型

我们一起来了解 serviceComb 微服务的完整线程模型, IO 线程和业务线程之间的关系。

servicecComb 微服务的完整线程模型如下图所示:
在这里插入图片描述

通信协议

通过上面的线程模型的分析,我们发现最终业务线程和服务端线程通信的关键就在于他们的网络连接和网络通信的过程,所以我们现在一起来学习一下 ServiceComb 中常用的通信协议有哪些?
在这里插入图片描述
我们通过下面的图可以看出有三种协议方式:

  • 第一种 : HighWay 方式,这种方式其实就是我们常说的 RPC 方式。
  • 第二种: Vertx REST 方式,这种方式也可以实现 WEB 开发,但我们一起用的少。
  • 第三种: Servlet REST 方式,这种方式是我们现在用的最多的一种方式。

九、开发 RESTFUL 方式微服务入门程序

首先我们以 rest 方式来开发 servicecomb 的入门程序,通过该程序我们能够掌握 servicecomb 微服务框架的 restful 方式开发基本步骤。

该程序的基本技术架构: springboot+servicecomb

服务程序基本结构

我们所构建的 servicecomb 入门程序的基本结构,如下图所示:
在这里插入图片描述
工程之间的结构关系,如下图所示:
在这里插入图片描述

父工程 servicecombrest 坐标引入

在父工程中 servicecombrest 的 pom.xml 文件中添加相关的坐标。

<?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.itheima</groupId>
    <artifactId>servicecombtest</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>service-interfaces</module>
        <module>service-provider</module>
        <module>service-consumer</module>
    </modules>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <!--1.实现pom文件导入-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.servicecomb</groupId>
                <artifactId>java-chassis-dependencies</artifactId>
                <version>1.0.0-m2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

子模块-服务接口 serviceinterfaces

打开 serviceinterface 子模块,并进入 src/main/java 目录下,创建 RestService 类

具体代码如下所示:

package com.itheima.service;

//微服务接口定义
public interface RestService {
    
    
    String sayRest(String name);
}

子模块-服务提供者 serviceprovider

打开模块后,模块结构图如下所示:
在这里插入图片描述
进入子模块 serviceprovider,打开 pom.xml 文件,添加如下坐标:

<?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">
    <parent>
        <artifactId>servicecombtest</artifactId>
        <groupId>com.itheima</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-provider</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--hibernate校验规则-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--rest支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>

        <!--ServiceComb提供的支持-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>spring-boot-starter-provider</artifactId>
        </dependency>
        <!--springboot与web整合-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>handler-flowcontrol-qps</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>handler-bizkeeper</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>handler-tracing-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>com.itheima</groupId>
            <artifactId>service-interfaces</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

编写 microservice.yaml 文件,具体配置如下:

APPLICATION_ID: start.servicecomb.io
service_description:
  name: provider
  version: 0.0.1
servicecomb:
  circuitBreaker:
     Provider:
       provider:
		 requestVolumeThreshold: 8
  fallbackpolicy:
     provider:
	   policy: returnnull
  flowcontrol:
    Provider:
	  qps:
		limit:
		  gateway: 100
  handler:
 	chain:
	  Provider:
 		default: qps-flowcontrol-provider,bizkeeper-provider,tracing-provider
  rest:
	address: 0.0.0.0:9080
  service:
	registry:
	address: http://192.168.229.133:30100
	autodiscovery: false

编写服务端 RestService 接口的实现类 RestProviderServiceImpl,如下所示:

package com.itheima.service.impl;

import com.itheima.service.RestService;
import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 以 rest 形式发布服务
 */
@RestSchema(schemaId = "hello")
@RequestMapping("/hello")
public class RestServiceImpl implements RestService {
    
    
    @Override
    @GetMapping("/hello")
    public String sayRest(String name) {
    
    
        return "Hello World " + name;
    }
}

编写 springboot 的服务启动类,代码如下:

package com.itheima;

import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * microservice.yaml 名称不得修改
 */
@SpringBootApplication
@EnableServiceComb //向注册中心进行注册
public class RestSpringBootApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(RestSpringBootApplication.class, args);
    }
}

完成后,就可以启动 ServiceComb 的服务提供者程序。

子模块-服务消费者 serviceconsumer

进入服务消费方,打开子模块 serviceconsumer 工程,打开它下面的 pom.xml 文件,并加入如下坐标:

<?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">
    <parent>
        <artifactId>servicecombtest</artifactId>
        <groupId>com.itheima</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-consumer</artifactId>

    <dependencies>
        <!--hibernate校验规则-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>

        <!--rest支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>

        <!--ServiceComb提供的支持-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>spring-boot-starter-provider</artifactId>
        </dependency>
        <!--springboot与web整合-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>handler-flowcontrol-qps</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>handler-bizkeeper</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>handler-tracing-zipkin</artifactId>
        </dependency>
        <!--service-interface-->
        <dependency>
            <groupId>com.itheima</groupId>
            <artifactId>service-interfaces</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
服务消费者 serviceconsumer 模块

目录结构如下:
在这里插入图片描述

编写 RestService 接口的实现类
package com.itheima.service.impl;

import com.itheima.service.RestService;
import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * 消费者的服务接口实现类
 */
@Service
public class RestConsumerServiceImpl implements RestService {
    
    
    //RestTemplate模板
    private final RestTemplate restTemplate = RestTemplateBuilder.create();//使用ServiceComb提供的类

    @Override
    public String sayRest(String name) {
    
    
        String provideName = "provider";
        //URL:cse://是协议    +  微服务名称   +具体某个微服务的访问路径
        String rtnValue = restTemplate.getForObject("cse://" + provideName + "/hello/hello?name=" + name, String.class);
        return rtnValue;
    }
}
编写 Controller 类
package com.itheima.controller;

import com.itheima.service.RestService;
import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RestSchema(schemaId = "test")
@RequestMapping("/test")
public class RestConsumerController {
    
    

    @Autowired
    private RestService restService;

    @GetMapping("/test")
    public String sayRest(String name) {
    
    
        return restService.sayRest(name);
    }
}
编写 Springboot 启动类
package com.itheima;

import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableServiceComb
public class ConsumerApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

服务运行测试

  1. 打开 CSE 服务注册中心
  2. 启动微服务的服务提供者
  3. 启动服务消费者

总结

在这里插入图片描述

十、开发 RPC 方式微服务入门程序

通过以 REST 方式入门程序的介绍,我们基本理解了 ServiceComb 中服务的发布和消费。那么现在我们以 RPC 方式同样介绍一下 ServiceComb 的服务发布与消费。它们不一样的就是服务的开发方式,但最终效果都是一样的。

服务程序基本结构

我们所构建的 servicecomb 入门程序的基本结构,如下图所示:
在这里插入图片描述

父工程 service-rpc 坐标引入

在父工程中 service-rpc 的 pom.xml 文件中添加相关的坐标。

<?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.itheima</groupId>
    <artifactId>service-rpc</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>service-rpc-interface</module>
        <module>rpc-provider</module>
        <module>rpc-consumer</module>
    </modules>
    <!--继承的依赖父模块-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <!--导入servicecomb的核心配置的pom文件-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.servicecomb</groupId>
                <artifactId>java-chassis-dependencies</artifactId>
                <version>1.0.0-m2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!--编译插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

子模块-服务接口 service-rpc-interface

打开 service-rpc-interface 子模块,并进入 src/main/java 目录下,创建 RpcService 类

具体代码如下所示:

package com.itheima.service;

/**
 * 开发一个服务接口
 */
public interface RpcService {
    
    
    String sayRpc(String name);
}

子模块-服务提供者 service-rpc-provider

打开模块后,模块结构图如下所示:
在这里插入图片描述
进入子模块 service-rpc-provider,打开 pom.xml 文件,添加如下坐标:

<?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">
    <parent>
        <artifactId>service-rpc</artifactId>
        <groupId>com.itheima</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>rpc-provider</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.3.5.Final</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>spring-boot-starter-provider</artifactId>
        </dependency>
        <!--transport 根据 microservice.yaml 中 endpoint 发布需求选择,本例中两者都引入,也可以二选一-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>transport-rest-vertx</artifactId>
        </dependency>
        <!--rpc通信模型-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>transport-highway</artifactId>
        </dependency>
        <!--rpc编程模型-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>provider-pojo</artifactId>
        </dependency>
        <!--引入服务接口-->
        <dependency>
            <groupId>com.itheima</groupId>
            <artifactId>service-rpc-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>1.5.12.RELEASE</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/bin</outputDirectory>
                            <classifier>exec</classifier>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Class-Path>.</Class-Path>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

编写 microservice.yaml 文件,具体配置如下:

APPLICATION_ID: start.servicecomb.io
service_description:
  name: serviceprovider-rpc
  version: 0.0.1
  properties:
    allowCrossApp: true
servicecomb:
  handler:
    chain:
      Provider: {
    
    }
  highway:
    address: 0.0.0.0:9090
  service:
    registry:
      address: http://127.0.0.1:30100
      autodiscovery: false

编写服务端 RpcService 接口的实现类 RpcServiceImpl,如下所示:

package com.itheima.service.impl;

import com.itheima.service.RpcService;
import org.apache.servicecomb.provider.pojo.RpcSchema;

/**
 * PRC方式-服务提供者
 * schemaId = "helloRpc" 代表服务编号
 */
@RpcSchema(schemaId = "helloRpc")
public class RpcProviderServiceImpl implements RpcService {
    
    

    public String sayRpc(String name) {
    
    
        return "hello " + name;
    }
}

编写 springboot 的服务启动类,代码如下:

package com.itheima;

import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 服务启动类
 */
@SpringBootApplication
@EnableServiceComb
public class RpcProvdierApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(RpcProvdierApplication.class, args);
    }
}

完成后,就可以启动 ServiceComb 的服务提供者程序。

子模块-服务消费者 service-rpc-consumer

进入服务消费方,打开子模块 service-rpc-consumer 工程,打开它下面的 pom.xml 文件,并加入如下坐标:

<?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">
    <parent>
        <artifactId>service-rpc</artifactId>
        <groupId>com.itheima</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>rpc-consumer</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.3.5.Final</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>spring-boot-starter-provider</artifactId>
        </dependency>

        <!--web模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--transport 根据 microservice.yaml 中 endpoint 发布需求选择,本例中两者都引入,也可以二选一-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>transport-rest-vertx</artifactId>
        </dependency>
        <!--rpc通信模型-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>transport-highway</artifactId>
        </dependency>
        <!--rpc编程模型-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>provider-pojo</artifactId>
        </dependency>
        <!--引入服务接口-->
        <dependency>
            <groupId>com.itheima</groupId>
            <artifactId>service-rpc-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>1.5.12.RELEASE</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/bin</outputDirectory>
                            <classifier>exec</classifier>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Class-Path>.</Class-Path>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
编写controller
package com.itheima.controller;

import com.itheima.service.RpcService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 *对外发布的控制类
 */
@RestController
public class RpcConsumerController {
    
    
    @Autowired
    private RpcService rpcService;

    @RequestMapping("/rpc")
    public void rpcInvoke(){
    
    
        System.out.println(rpcService.sayRpc(" servicecomb rpc "));
    }
}
编写 RestService 接口的实现类
package com.itheima.service.impl;

import com.itheima.service.RpcService;
import org.apache.servicecomb.provider.pojo.RpcReference;
import org.springframework.stereotype.Component;

/**
 * RPC-服务消费者
 */
@Component
public class RestConsumerServiceImpl implements RpcService {
    
    

    //从注册中心找,找哪个应用程序下面的哪个微服务
    //microserviceName :代表了哪个应用程序编号:下面的哪个应用名
    //schemaId="",它的值来自于服务提供者中用@RpcSchema(schemaId = "helloRpc")
    @RpcReference(microserviceName = "start.servicecomb.io:serviceprovider-rpc", schemaId = "helloRpc")
    private RpcService rpcService;//从注册中心推送过来

    public String sayRpc(String name) {
    
    
        return rpcService.sayRpc(name);
    }
}
编写Springboot启动类
package com.itheima;

import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 启动类.
 */
@SpringBootApplication
@EnableServiceComb
public class RestConsumerApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(RestConsumerApplication.class,args);
    }
}

服务运行测试

  1. 打开 CSE 服务注册中心
  2. 启动微服务的服务提供者
  3. 启动服务消费者

总结

在这里插入图片描述

十一、ServiceComb 服务治理方案

为了引入 ServiceComb 的服务治理策略,我们可以加入相关配置。

首先,需要在 pom.xml 文件中加入相关的坐标

<!--限流-->
<dependency>
    <groupId>org.apache.servicecomb</groupId>
    <artifactId>handler-flowcontrol-qps</artifactId>
</dependency>
<!--熔断包-->
<dependency>
    <groupId>org.apache.servicecomb</groupId>
    <artifactId>handler-bizkeeper</artifactId>
</dependency>
<!--日志追踪-->
<dependency>
    <groupId>org.apache.servicecomb</groupId>
    <artifactId>handler-tracing-zipkin</artifactId>
</dependency>

其次,需要在 microservice.yaml 配置文件中加入相关的治理策略,如下所示

APPLICATION_ID: start.servicecomb.io
service_description:
  name: provider
  version: 0.0.1
servicecomb:
  circuitBreaker: #熔断
    Provider:
      provider:
        requestVolumeThreshold: 8
  fallbackpolicy:
    provider:
      policy: returnnull
  flowcontrol: #限流
    Provider:
      qps:
        limit:
          gateway: 1
  handler:
    chain:
      Provider:
        default: qps-flowcontrol-provider,bizkeeper-provider
  rest:
    address: 0.0.0.0:9080
  service:
    registry:
      address: http://127.0.0.1:30100
      autodiscovery: false

ServiceComb 提供了基于 Ribbon 的负载均衡方案,用户可以通过配置文件配置负载均衡策略,当前支持随机、顺序、基于响应时间的权值等多种负载均衡路由策略。

负载均衡策略

作为 ServiceComb 内置策略,我们测试一下执行效果。

首先,将服务提供者的启动类设置为共享( Share)模式。如下图所示:
在这里插入图片描述
其次:修改服务提供者的 Service 类,加入一行输出代码。
在这里插入图片描述
运行 SpringBoot 启 动类。之后再次修改 microservice.yaml 文件,将端口号改为 8082 再次运行启动类

  rest:
    address: 0.0.0.0:9082

再次:运行服务消费者,观察控制台,我们会发现此时不断访问时,控制台上会更替出现输出信息。

限流策略

限流是微服务框架基本都可以解决的一个策略,是微服务框架中常见的系统保障措施。 通常来说系统的吞吐量是可以提前预测的,当请求量超过预期的伐值时可以采取一些限制措施来保障系统的稳定运行,比如延迟处理、拒绝服务等。

ServiceComb 微服务框架限流主要是基于 zuul 网关来实现限流的。通常需要先配置好 zuul 网关。

本次实验:我们再次添加一个 gate 网关模块。

第一步:添加 pom.xml 文件中的 Zuul 网关依赖:

<!-- zuul proxy 需要的包-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.servicecomb</groupId>
    <artifactId>spring-cloud-zuul-zipkin</artifactId>
</dependency>

第二步: 添加 application.yml 文件,配置如下:

server:
  port: 9003
zuul:
  routes:
    shicifang-friend:
      serviceId: shicifang-friend
    shicifang-qa:
      serviceId: shicifang-qa
discoveryServer:
  ribbon:
      eureka:
        enabled: false
servicecomb:
  tracing:
    enabled: true

第三步:添加 Zuul 网关的启动类

package com.itheima;

import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@SpringBootApplication
@EnableServiceComb
@EnableZuulProxy//新增注
public class ZuulSpringBootApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ZuulSpringBootApplication.class, args);
    }

    @Bean
    public CorsFilter corsFilter() {
    
    
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许 cookies 跨域
        config.addAllowedOrigin("*");// #允许向该服务器提交请求的 URI, *表示全部允许,在SpringMVC 中,如果设成*,会自动转成当前请求头中的 Origin
        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.addAllowedMethod("OPTIONS");// 允许提交请求的方法, *表示全部允许
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");// 允许 Get 的请求方法
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

第四步:在 ServiceComb 的配置文件 mircoservice.yaml 中添加如下配置:

servicecomb:
  flowcontrol: #限流
    Provider:
      qps:
        limit:
          gateway: 1000
  handler:
    chain:
      Provider:
        default: qps-flowcontrol-provider,bizkeeper-provider,tracing-provider

WEBUI 测试频繁刷新 10 次观看查询次数查看调用次数, 有部分服务调用没有成功

System.out.println(“微服务 1 调用”);

把 1 修改为 1000, 频繁访问 WEBUI 测试地址。查看调用次数

System.out.println(“微服务 1 调用”); http:状态码 429 太多访问

熔断机制

CircuitBreaker 就是熔断的意思。

熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。

服务雪崩效应:
在这里插入图片描述
服务熔断过程:
在这里插入图片描述
microservice.yaml 文件配置:

servicecomb:
  circuitBreaker: #熔断
    provider:
      shicifang-qa:
        requestVolumeThreshold: 1
  fallbackpolicy:
    provider:
      policy: returnnull

测试:

后台:

先启动 shicifang-friend,再启动 shgicifang-qa,最后启动 shicifang-gateway-web。

前端:

使用 web 前端访问 test.htm,返回问题列表后,停掉 mysql 数据库,观察 shicifang-friend 控制台日志,

当服务抛出异常后,多次调用就不在输出 22222 了。启动数据库数据库,再次点击关注。服务启动成功。

十二、ServiceComb 综合案例-十次方交友与问题模块

案例需求说明

项目功能是,用户发布问题,客户对自己喜欢的用户点关注。类似粉丝订阅。本案例很好的使用 ServiceComb 实现了十次方项目中的用户发布问题,客户关注喜欢的问题。

案例架构分析

  • shicifang-friend:用户关注相关微服务
  • shicifang-qa:用户发帖相关微服
  • shicifang-gateway-web:网关访问微服务

在这里插入图片描述

案例数据库分析

CREATE TABLE `tb_friend` (
	`userid` varchar(20) NOT NULL COMMENT '用户 ID',
	`friendid` varchar(20) NOT NULL COMMENT '好友 ID',
	`islike` varchar(1) DEFAULT NULL COMMENT '是否互相喜欢',
	PRIMARY KEY (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_friend
-- ----------------------------
INSERT INTO `tb_friend` VALUES ('1', '1222', '0');
INSERT INTO `tb_friend` VALUES ('111', '1222', '0');
INSERT INTO `tb_friend` VALUES ('134732', '1222', '0');
INSERT INTO `tb_friend` VALUES ('13732', '1222', '0');
INSERT INTO `tb_friend` VALUES ('3432', '1222', '0');
INSERT INTO `tb_friend` VALUES ('555', '1222', '0');
INSERT INTO `tb_friend` VALUES ('90', '24105', '0');
CREATE TABLE `tb_nofriend` (
	`userid` varchar(20) NOT NULL COMMENT '用户 ID',
	`friendid` varchar(20) NOT NULL COMMENT '好友 ID',
	PRIMARY KEY (`userid`,`friendid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `tb_pl`;

CREATE TABLE `tb_pl` (
	`problemid` varchar(20) NOT NULL COMMENT '问题 ID',
	`labelid` varchar(20) NOT NULL COMMENT '标签 ID',
	PRIMARY KEY (`problemid`,`labelid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_pl
-- ----------------------------
INSERT INTO `tb_pl` VALUES ('1', '1');
DROP TABLE IF EXISTS `tb_problem`;

CREATE TABLE `tb_problem` (
	`id` varchar(20) NOT NULL COMMENT 'ID',
	`title` varchar(100) DEFAULT NULL COMMENT '标题',
	`content` text COMMENT '内容',
	`createtime` datetime DEFAULT NULL COMMENT '创建日期',
	`updatetime` datetime DEFAULT NULL COMMENT '修改日期',
	`userid` varchar(20) DEFAULT NULL COMMENT '用户 ID',
	`nickname` varchar(100) DEFAULT NULL COMMENT '昵称',
	`visits` bigint(20) DEFAULT NULL COMMENT '浏览量',
	`thumbup` bigint(20) DEFAULT NULL COMMENT '点赞数',
	`reply` bigint(20) DEFAULT NULL COMMENT '回复数',
	`solve` varchar(1) DEFAULT NULL COMMENT '是否解决',
	`replyname` varchar(100) DEFAULT NULL COMMENT '回复人昵称',
	`replytime` datetime DEFAULT NULL COMMENT '回复日期',
	PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='问题';

-- ----------------------------
-- Records of tb_problem
-- ----------------------------
INSERT INTO `tb_problem` VALUES ('1', '这是个问题', '代码调试不通咋办? ', '2018-01-08 11:50:50', '2018-01-09 11:50:54', '2', null, '101', null, null, null, null, null);
DROP TABLE IF EXISTS `tb_reply`;

CREATE TABLE `tb_reply` (
	`id` varchar(20) NOT NULL COMMENT '编号',
	`problemid` varchar(20) DEFAULT NULL COMMENT '问题 ID',
	`content` text COMMENT '回答内容',
	`createtime` datetime DEFAULT NULL COMMENT '创建日期',
	`updatetime` datetime DEFAULT NULL COMMENT '更新日期',
	`userid` varchar(20) DEFAULT NULL COMMENT '回答人 ID',
	`nickname` varchar(100) DEFAULT NULL COMMENT '回答人昵称',
	PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='回答';
-- ----------------------------
-- Records of tb_reply
-- ----------------------------
INSERT INTO `tb_reply` VALUES ('', '1', null, null, null, null, null);
INSERT INTO `tb_reply` VALUES ('2', '1', '问老师呗', '2018-01-10 14:14:06', null, '1', null);
INSERT INTO `tb_reply` VALUES ('3', '2', '明天再调', '2018-01-07 14:14:13', null, '1', null);
DROP TABLE IF EXISTS `tb_ul`;

CREATE TABLE `tb_ul` (
	`uid` varchar(20) NOT NULL COMMENT '用户 ID',
	`lid` varchar(20) NOT NULL COMMENT '标签 ID',
	PRIMARY KEY (`uid`,`lid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

十次方交友与问答模块结构

在这里插入图片描述
在这里插入图片描述

Shicifang 父工程的 pom.xml,如下所示:

<?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>cn.itcast</groupId>
    <artifactId>shicifang</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>shicifang-common</module>
        <module>shicifang-friend-interface</module>
        <module>shicifang-friend</module>
        <module>shicifang-gateway-web</module>
        <module>shicifang-qa</module>
    </modules>
    <packaging>pom</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <fastjson.version>1.2.47</fastjson.version>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.12.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.servicecomb</groupId>
                <artifactId>java-chassis-dependencies</artifactId>
                <version>1.0.0-m2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.7.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.20.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>

定义服务接口

在 shicifang-friend-interface 模块中,添加服务接口,代码如下:

package com.tensquare.friend.service;

public interface FriendService {
    
    
    public int addFriend(String userid, String friendid);
}

引入十次方项目的通用模块

十次方的 shicifang-common 通用模块结构如下图:
在这里插入图片描述

开发十次方的交友微服务

在 shicifang-friend 模块中,开发交友微服务,关键代码如下:

package com.tensquare.friend.cse;

import com.tensquare.friend.service.FriendService;
import entity.Result;
import entity.StatusCode;
import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestSchema(schemaId = "friend")
@RequestMapping("/friend")
public class FriendRestService {
    
    
    @Autowired
    private FriendService friendService;

    @GetMapping(path = "/like")
    public String addFriend(String friendid, String userid) {
    
    
        System.out.println(22222);
        friendService.addFriend(userid, friendid);
        return "1";
    }
}

在microservice.yaml 中配置微服务名称为 shicifang-friend。文件配置如下:

APPLICATION_ID: start.servicecomb.io #应用名称
service_description:
  name: shicifang-friend #微服务名称
  version: 0.0.1  #微服务版本号
servicecomb:
  tracing: #日志收集器配置
    collector:
      address: http://127.0.0.1:9411
  circuitBreaker: #服务熔断
    Provider:
      shicifang-friend:
        requestVolumeThreshold: 8 #10 秒内发生多少次失败后熔断.注意由于 m2 存在一个 BUG,如果设置为 N,实际上生效的值是 N-1
  fallbackpolicy:
    provider:
      policy: returnnull
  flowcontrol:  #限流配置
    Provider:
      qps:
        limit:
          gateway: 1000
  handler: #服务处理方式包括限流、熔断、日志追踪
    chain:
      Provider:
        default: qps-flowcontrol-provider,bizkeeper-provider,tracing-provider
  rest: #rest 方式方式调用微服务,多个微服务启动注意端口冲突问题
    address: 0.0.0.0:9081
  service:
    registry: #服务注册中心地址,端口默认 30100
      address: http://127.0.0.1:30100

开发十次方的问答微服务

在 shicifang-qa 模块中开发问答微服务,代码如下:

package com.tensquare.qa.controller;

import com.tensquare.friend.service.FriendService;
import com.tensquare.qa.pojo.Problem;
import com.tensquare.qa.service.ProblemService;
import com.tensquare.qa.vo.UserVO;
import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE;

/**
 * 微服务
 */
@RestSchema(schemaId = "problem-qa")
@RequestMapping(path = "/problem-qa")
public class ProblemController {
    
    
    @Autowired
    private FriendService friendService;

    @Autowired
    private ProblemService problemService;

    /**
     * 查询全部数据
     */
    @RequestMapping(path = "/", method = RequestMethod.GET, produces = APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public ResponseEntity<List> findAll(String userid, String friendid) {
    
    
        System.out.println("微服务2调用");
        return new ResponseEntity<>(problemService.findAll(), null, OK);
    }

    /**
     * 新增用户关注
     */
    @RequestMapping(path = "/", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<String> addFridend(@RequestBody UserVO userVO) {
    
    
        //调用微服务关注
        java.util.Random r = new java.util.Random();
        int returnState = friendService.addFriend(r.nextInt() + "", userVO.getFriendid());

        //新增一个问题
        Problem problem = new Problem();
        problem.setContent("哈哈啊");
        problemService.add(problem);

        return new ResponseEntity<String>(String.valueOf(returnState), null, OK);
    }
}

在microservice.yaml 文件配置如下:

APPLICATION_ID: start.servicecomb.io
service_description:
  name: shicifang-qa
  version: 0.0.2
servicecomb:
  tracing:
    collector:
      address: http://127.0.0.1:9411
  circuitBreaker:
    Provider:
      shicifang-friend:
        requestVolumeThreshold: 8
  fallbackpolicy:
    provider:
      policy: returnnull
  flowcontrol:
    Provider:
      qps:
        limit:
          gateway: 1000
  handler:
    chain:
      Provider:
        default: qps-flowcontrol-provider,bizkeeper-provider,tracing-provider
  rest:
    address: 0.0.0.0:9083
  service:
    registry:
      address: http://127.0.0.1:30100

添加允许跨域请求的过滤器

package cn.itcast;

import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@SpringBootApplication
@EnableServiceComb
@EnableZuulProxy//新增注
public class ZuulSpringBootApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ZuulSpringBootApplication.class, args);
    }

    @Bean
    public CorsFilter corsFilter() {
    
    
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许cookies跨域
        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.addAllowedMethod("OPTIONS");// 允许提交请求的方法,*表示全部允许
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");// 允许Get的请求方法
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

开发十次方的服务调用者-前端页面

在前端测试页面 test.html 中,加入 ajax 方式访问微服务。代码如下:

<script type="text/javascript" src="jquery-3.3.1.js"></script>
<script>	
     $.ajax({
    
    
       url: 'http://127.0.0.1:9003/shicifang-qa/problem-qa/?userid=3432&friendid=1222',
       type: "GET",
       success: function (data) {
    
    
         $(".div-border").empty();
       	$.each(data,function(i,data){
    
    
       		 var html = "<div class='content-div'>";
            html+="<p>"
            html+="<b>"+data.title+"</b><br>"
            html+="<b>"+data.content+"</b><br>"
            html+="<input type='button' value='关注'  οnclick='guanzhu("+data.userid+")'>"		      
            html+="</p>"
            html+="</div>"
            $(".div-border").append(html)
     });       
       }	
       ,error: function (xhr) {
    
    
       	 console.log("连接异常")
       	
       }
     });
     
     function guanzhu(userid){
    
    
     	var dataParam = {
    
    
       	"userid":userid,
       	"friendid":1234
       };
     	
       $.ajax({
    
    
       url: 'http://127.0.0.1:9003/shicifang-qa/problem-qa/',
       type: "POST",
       data:JSON.stringify(dataParam),
       contentType: "application/json; charset=utf-8",
       success: function (data) {
    
    
          console.log("关注成功")
       }	
       ,error: function (xhr) {
    
    
       	 console.log("关注失败")
       }
         });
     }
</script>

测试微服务发布与调用

  1. 开启 CSE 服务注册中心
  2. 运行 shicifang-friend 模块
  3. 运行 shicifang-qa 模块
  4. 运行 shicifang-gate-web 模块
  5. 运行十次方前端 test.html,刷新页面可以看到微服务调用成功

代码仓库


猜你喜欢

转载自blog.csdn.net/weixin_44950987/article/details/108178963