Spring Cloud

Spring-cloud简述

2020-01-08  本文已影响0人  星可码农

spring-cloud最常用的5个部分

服务发现注册中心——Netflix Eureka
客服端负载均衡——Netflix Ribbon
断路器——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config

Eureka

Eureka 是 Netflix 开发的,一个基于 REST 服务的,服务注册与发现的组件
主要有两个组件:Eureka Server 和 Eureka Client
Eureka Client:一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)
Eureka Server:提供服务注册和发现的能力(通常就是微服务中的注册中心)

Eureka Client 客户端服务启动会向 Eureka Server注册自己的服务,Eureka Server会存储该服务信息,并定时的检测服务的运行状态。

Eureka Server部署pom文件配置

注意版本匹配问题:spring-cloud Greenwich.M3对应java1.8以上,与 Spring Boot 2.1.0.RELEASE 兼容

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.M3</spring-cloud.version>
    </properties>

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

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

    <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>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <finalName>service-eureka</finalName>
    </build>

启动类注意注解

@SpringBootApplication
//创建服务注册中心
@EnableEurekaServer
public class StartMain {
    public static void main(String[] args) {
        SpringApplication.run(StartMain.class, args);
    }
}

Hystrix

参考项目:https://gitee.com/lfalex/springcloud-example/tree/master/eureka-feign-hystrix-client/src/main/java/com/cn/feign

Hystrix简介

Hystrix(https://github.com/Netflix/Hystrix)是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性、容错性与局部应用的弹性,是一个实现了超市机制和断路器模式的工具类库

Hystrix如何解决依赖隔离

image

 1、包裹请求:使用HystrixCommand包裹对依赖的调用逻辑,每个命令在独立的线程中执行,使用了设计模式中的“命令模式”;
  2、跳闸机制:当某服务的错误率超过一定阈值时,Hystrix可以自动或者手动跳闸,停止请求该服务一段时间;
  3、资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程已满,则发向该依赖的请求就会被立即拒绝,而不是排队等候,从而加速失败判定;
  4、监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等;
  5、回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑,回退逻辑由开发人员自行提供,如返回一个缺省值;
  6、自我修复:断路器打开一段时间后,会自动进入“半开”状态,此时断路器可允许一个请求访问依赖的服务,若请求成功,则断路器关闭,否则断路器转为“打开”状态;

代码如下:
启动类:

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableDiscoveryClient
public class ServiceMobApplication {

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

}

测试接口:

@FeignClient(name = "service-mob", fallback = FeignClientFallback.class)
public interface ServiceMobFeignClient {


    @PostMapping("/testFeignHystrix")
    public String testFeignHystrix();

}

接口回调服务类:

@Component
class FeignClientFallback implements ServiceMobFeignClient {

    @Override
    public String testFeignHystrix() {
        System.out.println("熔断,默认回调函数");
        return "{\"username\":\"admin\",\"age\":\"-1\"}";
    }
}

配置文件添加:

#控制接口熔断
feign:
  hystrix:
    enabled: true

参考文档:https://www.jianshu.com/p/9b1f658f1569

ribbon

image.png

原文链接:https://blog.csdn.net/mytobaby00/article/details/79837382

zuul

什么是Zuul?

Spring Cloud Zuul是整合Netflix公司的Zuul开源项目实现的微服务网关,它实现了请求路由、负载均衡、校验过滤等 功能。官网:https://github.com/Netflix/zuul

网关作用:服务网关是在微服务前边设置一道屏障,请求先到服务网关,网关会对请求进行过滤、校验、路由等处理。有了服务网关可以提高微服务的安全性,网关校验请求的合法性,请求不合法将被拦截,拒绝访问。

搭建网关工程

创建一个微服务工程引入依赖

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

添加注解

在启动类上使用@EnableZuulProxy注解标识此工程为Zuul网关,启动类代码如下:

package com.qqxhb.springcloud.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy // 此工程是一个zuul网关
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}
```
### 配置路由
**注意事项hystrix超时时间最好不要小于zuul的超时时间,防止断路器重试**
```
server:
  #服务端口号
  port: 8085
spring:
  application:
    #服务名称 - 服务之间使用名称进行通讯
    name: service-zuul
eureka:
  client:
    service-url:
      #填写注册中心服务器地址
      defaultZone: http://localhost:8080/eureka
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
zuul:
  routes:
    #设置服务user 路径名称 随便起
    service-user:
      path: /service-user/**
      #这里写user服务的注册名字
      serviceId: service-user
    #设置服务mob 路径名称 随便起
    service-mob:
      path: /service-mob/**
      #这里写b服务的注册名字
      serviceId: service-mob
    max:
      host:
        connections: 500
    host:
        socket-timeout-millis: 60000
        connect-timeout-millis: 60000
##timeout config
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 60000
ribbon:
  #建立连接超时时间
  ReadTimeout: 60000
  #读取资源超时间
  ConnectTimeout: 60000
```
### 过滤器

Zuul的核心就是过滤器,通过过滤器实现请求过虑,身份校验等。在zuul中过滤器分为四种:

PRE Filters(前置过滤器) :当请求会路由转发到具体后端服务器前执行的过滤器,比如鉴权过滤器,日志过滤器,还有路由选择过滤器
ROUTING Filters (路由过滤器):该过滤器作用是把请求具体转发到后端服务器上,一般是通过Apache HttpClient 或者 Netflix Ribbon把请求发送到具体的后端服务器上
POST Filters(后置过滤器):当把请求路由到具体后端服务器后执行的过滤器;场景有添加标准http 响应头,收集一些统计数据(比如请求耗时等),写入请求结果到请求方等。
ERROR Filters(错误过滤器):当上面任何一个类型过滤器执行出错时候执行该过滤器

自定义过虑器需要继承 ZuulFilter,ZuulFilter是一个抽象类,需要覆盖它的四个方法,如下:

shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true表示要执行此过虑器,否则不执行。
run:过滤器的业务逻辑。
filterType:返回字符串代表过滤器的类型
filterOrder:此方法返回整型数值,通过此数值来定义过滤器的执行顺序,数字越小优先级越高。
```
package com.qqxhb.springcloud.gateway.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.qqxhb.springcloud.gateway.service.AuthService;
import com.qqxhb.springcloud.model.response.CommonCode;
import com.qqxhb.springcloud.model.response.ResponseResult;

/**
 * 身份校验过滤器
 * 
 * @author Administrator
 * @version 1.0
 **/

@Component
public class LoginFilter extends ZuulFilter {

    @Autowired
    AuthService authService;

    /**
     * 过滤器的类型
     * 
     * pre:请求在被路由之前执行
     * 
     * routing:在路由请求时调用
     * 
     * post:在routing和errror过滤器之后调用
     * 
     * error:处理请求时发生错误调用
     * 
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 过滤器序号,越小越被优先执行
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 返回true表示要执行此过滤器
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 过滤器的内容
     * 
     * 测试的需求:过虑所有请求,判断头部信息是否有Authorization,如果没有则拒绝访问,否则转发到微服务。
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        // 得到request
        HttpServletRequest request = requestContext.getRequest();
        // 取cookie中的身份令牌
        String tokenFromCookie = authService.getTokenFromCookie(request);
        if (StringUtils.isEmpty(tokenFromCookie)) {
            // 拒绝访问
            access_denied();
            return null;
        }
        // 从header中取jwt
        String jwtFromHeader = authService.getJwtFromHeader(request);
        if (StringUtils.isEmpty(jwtFromHeader)) {
            // 拒绝访问
            access_denied();
            return null;
        }
        // 从redis取出jwt的过期时间
        long expire = authService.getExpire(tokenFromCookie);
        if (expire < 0) {
            // 拒绝访问
            access_denied();
            return null;
        }
        return null;
    }

    // 拒绝访问
    private void access_denied() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        // 得到response
        HttpServletResponse response = requestContext.getResponse();
        // 拒绝访问
        requestContext.setSendZuulResponse(false);
        // 设置响应代码
        requestContext.setResponseStatusCode(200);
        // 构建响应的信息
        ResponseResult responseResult = new ResponseResult(CommonCode.UNAUTHENTICATED);
        // 转成json
        String jsonString = JSON.toJSONString(responseResult);
        requestContext.setResponseBody(jsonString);
        // 转成json,设置contentType
        response.setContentType("application/json;charset=utf-8");
    }
}
```
3 微服务之间认证
由于资源微服务需要校验JWT授权,当微服务访问微服务,此时如果没有携带JWT则微服务会在授权时报错。解决方案就是微服务之间使用feign进行远程调用,采用feign拦截器实现远程调用携带JWT。为了方便个微服务使用,在公用工程中做如下操作:
1 、引入依赖

 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
2、定义Feign拦截器

package com.qqxhb.springcloud.interceptor;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import feign.RequestInterceptor;
import feign.RequestTemplate;

/**
 * Feign拦截器
 * 
 * @author Administrator
 * @version 1.0
 **/
public class FeignClientInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = requestAttributes.getRequest();
            // 取出当前请求的header,找到jwt令牌
            Enumeration<String> headerNames = request.getHeaderNames();
            if (headerNames != null) {
                while (headerNames.hasMoreElements()) {
                    String headerName = headerNames.nextElement();
                    String headerValue = request.getHeader(headerName);
                    // 将header向下传递
                    requestTemplate.header(headerName, headerValue);
                }
            }
        }
    }
}

3、在需要远程调用的微服务启动类注入拦截器

@Bean
    public FeignClientInterceptor getFeignClientInterceptor() {
        return new FeignClientInterceptor();
    }

参考文档链接:https://blog.csdn.net/qq_43792385/article/details/93745835


##spring-config
##分布式配置中心

Spring Cloud Config 是用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,它分为服务端与客户端两个部分。其中服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息、加密 / 解密信息等访问接口;而客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定的配置中心来管理应用资源与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。Spring Cloud Config 实现了对服务端和客户端中环境变量和属性配置的抽象映射,所以它除了适用于 Spring 构建的应用程序之外,也可以在任何其他语言运行的应用程序中使用。由于 Spring Cloud Config 实现的配置中心默认采用 Git 来存储配置信息,所以使用 Spring Cloud Config 构建的配置服务器,天然就支持对微服务应用配置信息的版本管理,并且可以通过 Git 客户端工具来方便的管理和访问配置内容。当然它也提供了对其他存储方式的支持,比如:SVN 仓库、本地化文件系统

pom文件引入‘
```
    <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
```
启动文件添加注解
@EnableConfigServer

配置文件做以下修改:
引入配置文件:bootstrap.yml
```
spring:
  application:
    name: config-client
  profiles:
    active: dev
  cloud:
    config:
      server:
        git:
           uri: http://192.168.1.140/java_developer/java_project.git
           username:****
          password: ***
          search-paths: conf
          #分支
          default-label: delete_circle_charge
```

配置规则详解
建的那几个测试文件的命名规则么?
config-client.yml
config-client-dev.yml
config-client-test.yml
config-client-prod.yml
这里的application可以自定义为其它的名称,这里可以用应用的名称,即应用名,后边的dev、test、prod这些都可以视为一个应用下多个不同的配置文件,可以当做环境名,以下均用环境名代称。

Config支持我们使用的请求的参数规则为:

/ { 应用名 } / { 环境名 } [ / { 分支名 } ]
/ { 应用名 } - { 环境名 }.yml
/ { 应用名 } - { 环境名 }.properties
/ { 分支名 } / { 应用名 } - { 环境名 }.yml
/ { 分支名 } / { 应用名 } - { 环境名 }.properties
上一篇下一篇

猜你喜欢

热点阅读