SpringCloud是一系列框架的集合,目的是将业务系统拆分成一个个微服务,服务于服务之间相互独立,支持水平扩展,高可用,微服务架构主要的功能有服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,Netflix虽然已经过时了,但是他框架集和其他微服务框架集作用差不多

微服务整体架构如下图,看看就好:




springcloud项目的模块划分 springcloud common 模块_微服务


Netflix主要使用下面的组件:

组件

描述

Eureka

服务注册中心、服务发现中心

Ribbon

负载均衡,服务如果是一个集群,会通过Ribbon实现负载均衡

Feign

服务于服务之间的调用

Hystrix

监控和熔断器,服务降级与数据统计

Zuul

网关,所有请求由网关转发到具体的服务

一、项目搭建

首先搭建一个聚合项目,结构如下:


springcloud项目的模块划分 springcloud common 模块_java_02


1. commons模块

commons模块是一个普通的Maven项目,存放JavaBean和工具类




2. dependency模块

SpringBoot和SpringCloud版本是有对应关系的,要保持版本对应,否则会出现运行不了的情况:

Spring Cloud Alibaba Version

Spring Cloud Version

Spring Boot Version

2021.0.1.0

Spring Cloud 2021.0.1

2.6.3

2.2.7.RELEASE

Spring Cloud Hoxton.SR12

2.3.12.RELEASE

2021.1

Spring Cloud 2020.0.1

2.4.2

2.2.6.RELEASE

Spring Cloud Hoxton.SR9

2.3.2.RELEASE

2.1.4.RELEASE

Spring Cloud Greenwich.SR6

2.1.13.RELEASE

2.2.1.RELEASE

Spring Cloud Hoxton.SR3

2.2.5.RELEASE

2.2.0.RELEASE

Spring Cloud Hoxton.RELEASE

2.2.X.RELEASE

2.1.2.RELEASE

Spring Cloud Greenwich

2.1.X.RELEASE

2.0.4.RELEASE(停止维护,建议升级)

Spring Cloud Finchley

2.0.X.RELEASE

1.5.1.RELEASE(停止维护,建议升级)

Spring Cloud Edgware

1.5.X.RELEASE

其他模块都依赖于dependency模块,主要做SpringBoot的版本控制:


<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <packaging>pom</packaging>

    <groupId>com.aruba</groupId>
    <artifactId>dependency</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dependency</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <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-starter-parent</artifactId>
                <version>2.3.7.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>


3. eureka模块

eureka模块就是我们首先使用的组件,用于服务注册和发现

二、Eureka

1. eureka服务端

eureka模块单独启动,作为服务端

1.1 依赖

导入eureka服务依赖:


<parent>
        <artifactId>dependency</artifactId>
        <groupId>com.aruba</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../dependency/pom.xml</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--eureka服务-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>


1.2 @EnableEurekaServer

SpringBoot启动类上添加@EnableEurekaServer注解开启Eureka:


@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

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

}


启动后可以访问到eureka界面:




1.3 配置Eureka服务地址

此时虽然可以访问页面,但是eureka服务并没有真正的启动,yml文件需要配置,需要注意的是application.name将会作为服务名注册到eureka中,后续调用方会使用该名称:


spring:
  application:
    name: aruba-eureka

server:
  port: 7000

eureka:
  instance:
    hostname: aruba-eureka
  client:
    service-url:
      # 指定eureka服务的地址
      defaultZone: http://127.0.0.1:7000/eureka
    # 当前项目关闭注册服务
    register-with-eureka: false
    # 当前项目关闭获取服务
    fetch-registry: false


2. eureka客户端

再次新建一个dept模块作为eureka的客户端,用于注册服务到eureka服务器

2.1 依赖

导入eureka客户端依赖:


<parent>
        <artifactId>dependency</artifactId>
        <groupId>com.aruba</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../dependency/pom.xml</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aruba</groupId>
            <artifactId>commons</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>


2.2 @EnableEurekaClient

使用@EnableEurekaClient注解开启Eureka客户端


@SpringBootApplication
@EnableEurekaClient
public class DeptApplication {

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

}


2.3 配置Eureka服务地址


spring:
  application:
    name: aruba-dept

server:
  port: 8000

eureka:
  client:
    service-url:
      # 指定eureka服务的地址
      defaultZone: http://127.0.0.1:7000/eureka


2.4 启动客户端服务

启动服务后,再次访问Eureka管理页面,可以看到新注册的服务:




三、Feign

有了服务提供者,注册中心,消费者就可以通过Feign调用提供者

1. 完善dept模块
1.1 Javabean

commons模块中创建实体类:WDept,用于服务与服务之间传输


@AllArgsConstructor
@NoArgsConstructor
@Data
public class WDept implements Serializable {
    /**
     * 部门编号
     */
    private Integer deptId;
    /**
     * 部门名称
     */
    private String dName;
}


1.2 service层

dept模块中编写相应的service层代码

接口:


public interface DeptService {
    String insertDept(WDept dept);
}


实现:


@Service
public class DeptServiceImpl implements DeptService {

    @Override
    public String insertDept(WDept dept) {
        return "收到:" + dept.toString();
    }

}


1.3 提供Controller

Feign本质上是通过http进行调用的,controller层对外提供接口:


@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;

    @RequestMapping("/insertDept")
    public String insertDept(@RequestBody WDept wDept) {
        return deptService.insertDept(wDept);
    }

}


2. 调用方模块

新建模块,作为调用方:




2.1 依赖

导入eureka客户端和openFeign依赖:


<parent>
        <artifactId>dependency</artifactId>
        <groupId>com.aruba</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../dependency/pom.xml</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aruba</groupId>
            <artifactId>commons</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>


2.2 yml文件配置

需要配置的和dept模块差不多:


spring:
  application:
    name: aruba-dept-api

server:
  port: 8001

eureka:
  client:
    service-url:
      # 指定eureka服务的地址
      defaultZone: http://127.0.0.1:7000/eureka


2.3 @EnableFeignClients

使用@EnableFeignClients注解配置启动类,表示作为服务调用方


@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class DeptApiApplication {

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

}


2.4 @FeignClient

使用@FeignClient注解接口,并指定调用服务名,对应application.name,定义一个和调用方接口一样的方法


@FeignClient("aruba-dept")
public interface DeptFeignClient {

    @RequestMapping("/insertDept")
    String insertDept(WDept dept);

}


2.5 使用Feign

在调用方controller层中,注入刚刚的接口,并调用:


@RestController
@CrossOrigin
public class DeptController {
    @Autowired
    private DeptFeignClient deptFeignClient;

    @RequestMapping("/insertDept")
    public String insertDept(@RequestParam("deptId") Integer id) {
        return deptFeignClient.insertDept(new WDept(id, "Feign"));
    }

}


尝试调用:




四、Robbin

Feign集成了Robbin,默认就支持负载均衡,默认使用轮询策略,一旦遇上服务集群就会触发

1. 配置多个yml




修改端口为:


server:
  port: 8010


server:
  port: 8011


server:
  port: 8012


2. 配置启动




配置多个启动项,并指定使用yml文件:--spring.profiles.active=xxx,这边对应就是1,2,3:




3. 调用接口

启动多个服务,并调用消费者接口:




效果:




五、Hystrix

hystrix作为保证整体服务可用的组件,拥有服务降级和服务熔断功能,当一个微服务无法访问或长时间无响应,hystrix会自动帮助调用方进行处理,防止出现服务雪崩,因为hystrix是集成在服务调用方

1. 依赖

dept-api模块导入hystrix依赖:


<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>


2. yml配置

添加hystrix相关配置:


spring:
  application:
    name: aruba-dept-api

server:
  port: 8001

eureka:
  client:
    service-url:
      # 指定eureka服务的地址
      defaultZone: http://127.0.0.1:7000/eureka

# 开启hystrix
feign:
  hystrix:
    enabled: true

# 请求超时时间
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000


3. @EnableHystrix

启动类添加@EnableHystrix注解:


@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class DeptApiApplication {

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

}


此时为服务提供方接口调用添加一个睡眠:


@Service
public class DeptServiceImpl implements DeptService {

    @Override
    public String insertDept(WDept dept) {
        System.out.println(dept);
        try {
            Thread.sleep(13000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "收到:" + dept.toString();
    }

}


再次调用接口,2秒后会出现500错误,表示hystrix生效了:




4. 失败处理

接下来就要指定hystrix服务降级后,进行自己的业务处理,实际上feign与hystrix已经结合,我们之前定义了DeptFeignClient接口,需要实现一个该接口的类作为降级回调处理类:


@Component
public class DeptFeignFallCallback implements DeptFeignClient {
    @Override
    public String insertDept(WDept dept) {
        return "服务发生错误";
    }
}


接口类的@FeignClient注解添加fallback属性值,指定为处理类:


@FeignClient(value = "aruba-dept", fallback = DeptFeignFallCallback.class)
public interface DeptFeignClient {

    @RequestMapping("/insertDept")
    String insertDept(WDept dept);

}


再次调用接口,会返回自定义回调处理的结果:




六、Hystrix仪表盘

Hystrix仪表盘是监测触发熔断数据统计的管理页面,配置好后可以方便查看信息

新建模块:




1. 导入依赖

除了web外,还需要actuatorhystrix-dashboard依赖


<parent>
        <artifactId>dependency</artifactId>
        <groupId>com.aruba</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../dependency/pom.xml</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
    </dependencies>


2. yml配置


spring:
  application:
    name: aruba-hystrix-client

server:
  port: 9000

hystrix:
  dashboard:
    proxy-stream-allow-list: "localhost"


3. @EnableHystrixDashboard

使用@EnableHystrixDashboard注解在启动类上:


@SpringBootApplication
@EnableHystrixDashboard
public class HystrixClientApplication {

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

}


启动后访问localhost:9000/hystrix,就可以看到管理界面了:




4. 模块中配置

仅仅有上面的配置是不够的,还需要指定监测服务的一些配置,我们监测的是使用hystrix的dept-api模块,所以在该模块中添加配置类:




配置类提供ServletRegistrationBean的注入,内容为:


@Configuration
public class DeptActuator {

    @Bean
    public ServletRegistrationBean getServletRegistrationBean(){

        HystrixMetricsStreamServlet mss = new HystrixMetricsStreamServlet();

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(mss);

        servletRegistrationBean.setName("servletRegistrationBean");
        servletRegistrationBean.setLoadOnStartup(1);
        servletRegistrationBean.addUrlMappings("/hystrix.stream");
        return servletRegistrationBean;
    }

}


5. 输入具体监测地址

管理中输入:http://localhost:8001/hystrix.stream,对应提供配置的dept-api模块的端口和配置的url




进入后,尝试访问服务接口后,有了数据,才会出现数据统计:




七、Zuul

Zuul是微服务中的网关,在所有微服务内部,所有请求都应该由网关进行转发请求,网关提供统一的对外接口,功能概念和nginx差不多,但是nginx处于更上的接入层,性能方面没有可比较性,而微服务的网关组件都和SpringBoot有着较好的融合,使用方便

新建模块:




1. 依赖

导入zuul依赖以及eureka客户端依赖:


<parent>
        <artifactId>dependency</artifactId>
        <groupId>com.aruba</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../dependency/pom.xml</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>


2. yml配置

争对对外的微服务配置路由,可以配置多条,一般使用服务的application.name作为配置名,path为反向代理后的访问前缀,serviceId为服务的application.name


spring:
  application:
    name: aruba-zuul

server:
  port: 8080

#配置一个路由器
zuul:
  routes:
    dept-api:
      path: /oapi/**
      serviceId: aruba-dept-api

#从eureka获取我们的服务器的真实ip地址
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:7000/eureka

  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}


3. @EnableZuulProxy

使用@EnableZuulProxy注解在启动类上:


@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ZuulApplication {

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

}


启动后,可以通过http://localhost:8080/oapi/xxx进行对dept-api模块的访问:




项目地址:

https://gitee.com/aruba/netflix-study.git