Spring Cloud应用

一、SpringCloud Eureka

1. Eureka简介

Eureka分类:

  • 服务注册中心(服务端)——Eureka Server
  • 服务对象(客户端)——Eureka Client。Eureka Client分为服务提供者服务消费者,其中服务消费者可能既是服务提供者又是服务消费者,服务提供者必须注入到注册中心,才能被服务消费者正常调用,单纯的服务消费者可以不注入到Eureak Server中

Eureka工作机制

1) 服务注册中心

  • 失效剔除:默认每隔60秒将当前清单中超时(默认90秒)没有续约的服务剔除出去
  • 自我保护:EurekaServer 在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%(通常由于网络不稳定导致)。 Eureka Server会将当前的实例注册信息保护起来, 让这些实例不会过期,尽可能保护这些注册信息。

2) 服务对象

服务提供者

  • 服务注册:启动的时候会通过发送REST请求将自己注册到Eureka Server上
  • 服务续约:服务提供者会维持一个心跳用来持续告诉Eureka Server,防止被剔除
  • 服务下线:当服务实例进行正常的关闭操作,会给Eureka Server发送一个服务下线的REST请求

服务消费者

  • 获取服务:当启动服务消费者时,会给Eureka Server发送REST请求,获取服务注册中心中的服务清单
  • 服务调用:获取到服务清单后,可以通过服务名称获取该服务的元数据信息

2. Eureka服务端

1)新建项目

使用IDEA新建一个SpringBoot项目,选择如下依赖。(Eureka Server依赖自动依赖Spring Web,故可以不选择此项)

Spring Cloud应用_第1张图片

2)配置

将配置文件改为yml后缀,做如下配置:

server:
  port: 8761

spring:
  application:
    # 应用名称,Eureka 注册界面显示的名称(默认全大写)
    name: SpringCloud-Eureka
  # 配置security账号密码,Eureka服务中心引入Security后,必须手动关闭CRFS验证
  security:
    user:
      name: admin
      password: 123456

eureka:
  instance:
    # 应用实例主机名
    hostname: localhost
  server:
    # 是否开启自我保护,默认为 true
    # 当Eureka服务器在短时间内丢失过多客户端时,自我保护模式可使服务端不再删除失去连接的客户端
    enable-self-preservation: false
  client:
    # 是否注册到 Eureka 服务中心,默认为true
    register-with-eureka: false
    # 是否拉取 Eureka 服务中心信息,默认为true
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3)验证

启动类上加上@EnableEurekaServer,启动项目,浏览器访问:http://localhost:8761, 得到如下界面说明配置成功

Spring Cloud应用_第2张图片

4)安全验证

前面输入URL就能获取我们的Eureka Server信息,肯定是不安全的,这里我们加入Spring Security安全验证,来保证安全。

pom中新增依赖:


	org.springframework.boot
	spring-boot-starter-security

配置文件中新增如下配置:

spring:
  # 配置security账号密码,Eureka服务中心引入Security后,必须手动关闭CRFS验证
  security:
    user:
      # 账号、密码信息
      name: admin
      password: 123456

关闭Security默认启用的CSRF检验:

/**
 * 关闭Security默认启用的CSRF检验
 *  Spring Security 4开始,默认启用CSRF机制,但是这会导致 Eureka客户端注入失败,
 *  故需将其CSRF检验设置为false,来保障 Eureka客户端正常注入
 * @author czm
 * @date 2021/3/15
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 直接关闭CSRF检验,此外还可以通过 ignoringAntMatchers(uri) 的方式来部分关闭CSRF检验,如下
         *  http.csrf().ignoringAntMatchers("/eureka/**");
         */
        http.csrf().disable();
        super.configure(http);
    }
}

重启项目,再次访问http://localhost:8761,会跳到登录界面,如下,账号密码就是上面配的 admin :123456,输入登录即可。

Spring Cloud应用_第3张图片

3. Eureka客户端

1)新建项目

Spring Cloud应用_第4张图片

或者你图方便,可以像Eureka服务中心一样,只引入server依赖,应为其自动依赖于上面的这两个依赖:

Spring Cloud应用_第5张图片

2)修改配置

server:
  port: 8000	# 端口

spring:
  application:
    name: SpringCloud-EurekaClient		# 应用名称

eureka:
  client:
    service-url:
      # Eureka地址,当Eureka服务中心没有使用Spring Security时,可以去掉admin:123456,否则必须加上,不然该项目会注入失败
      defaultZone: http://admin:123456@localhost:8761/eureka/		

3)验证

启动类新增@EnableEurekaClient或者@EnableDiscoveryClient(如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient。),启动项目,访问http://localhost:8761:

Spring Cloud应用_第6张图片

二、SpringCloud Config

1. Config简介

Spring Cloud Config是一个解决分布式系统的配置管理方案,为分布式系统外部化配置提供了支持,包含Config Server和Config Client两部分,Server提供配置文件存储,对外提供接口以获取配置文件的内容,Client通过接口获取数据,并初始化自己。

2. Config配置中心

1)新建项目

Spring Cloud应用_第7张图片

2)配置仓库

在Git上新建仓库文件

Spring Cloud应用_第8张图片

文件名spring-cloud-client-a-dev.yml由三部分组成:

  • ${application.name}——项目名称
  • ${spring.profiles.active}——版本/环境
  • 后缀——yml | properties

这里的spring-cloud-client-a就是项目名称,dev就是环境,后缀也可以换位properties

3)yml配置

server:
  port: 8762

spring:
  application:
    name: SpringCloud-Config
  cloud:
    config:
      server:
        git:
          # 远程Git地址,加不加.git后缀都行
          uri: https://gitee.com/chenzm_ob/spring-cloud-config-resource
          # 查找目录,即再该地址下的那个目录中去找我们的紫云
          search-paths: resource
          # 账号密码,私有仓库必须配置,共有仓库可以为空
          username:
          password:
          # 资源分支,默认就为master
          default-label: master

4)验证

启动类上新增@EnableConfigServer注解,启动项目,访问设置的资源,格式如下:

# 不加label默认为master分支
/{application}/{profile}[/{label}]
/{label}/{application}-{profile}.yml

如:

http://localhost:8762/spring-cloud-client-a/dev/master
http://localhost:8762/master/spring-cloud-client-a-dev.yml

第一种方式获取到的内容如下,文件里的内容再source中。

{
    "name":"spring-cloud-client-a",
    "profiles":[
        "dev"
    ],
    "label":null,
    "version":"22c4bcb8b3098502f97f7774b95b96174408e4a8",
    "state":null,
    "propertySources":[
        {
            "name":"https://gitee.com/chenzm_ob/spring-cloud-config-resource/file:E:\Cache\Temp\config-repo-6299963860127397661\resource\spring-cloud-client-a-dev.yml",
            "source":{
                "name":"czm",
                "age":22,
                "hobby.book":"Snowwalker",
                "hobby.anime":"斗罗大陆",
                "profile":"dev"
            }
        }
    ]
}

第二种方式获取到的数据格式于我们文件的格式一样,但是会有乱码,不过不重要,因为我们已经从Git上远程获取到资源了

name: czm
age: 22
hobby:
  book: Snowwalker
  anime: 鏂楃綏澶ч檰
profile: dev

3. Config客户端

客户端通过配置中心获取远程仓库数据。

1)新建项目

Spring Cloud应用_第9张图片

创建项目后新增如下两个文件:

新增获取配置文件数据的对象:

@Component
public class ClientA {
    
    // @Value 注解获取配置文件对应属性的值
    @Value("${name}")
    private String name;

    @Value("${age}")
    private int age;

    @Value("hobby.book")
    private String book;
    @Value("hobby.anume")
    private String anume;

    @Value("${profile}")
    private String profile;
    
    // get/set 方法 或使用 lombok

}

新增测试接口:

@RestController
public class ClientAController {

    // 注入ClientA对象
    @Resource
    private ClientA clientA;

    @GetMapping("/getA")
    public Object getClientA() {
        return clientA;
    }
}

2)配置

由于我们需要从远程获取配置文件,然后从配置文件获取需要的数据,故这里除了常规的application.yml配置外,还需要一个bootstrap.yml配置文件。

Spring Boot服务启动时会加载application.yml/application.properties配置文件,Spring Cloud中有”引导上下文“的概念,引导上下文会加载bootstrap.yml/bootstrap.properties配置文件,即bootstrap.yml/bootstrap.properties会在Spring Boot服务启动之前加载,具有更高的优先级。默认情况下bootstrap.yml/bootstrap.properties中的属性不能被覆盖。

从Spring Boot 2.4版本开始,配置文件加载方式进行了重构。因此若要使用bootstrap.yml来进行配置,需要在pom中增加一个依赖,否则bootstrap.yml配置不生效:


    org.springframework.cloud
    spring-cloud-starter-bootstrap

bootstrap.yml配置文件:

spring:
  application:
    name: SpringCloud-ClientA1
  profiles:
    active: dev
  cloud:
    config:
      uri: http://localhost:8762
      name: spring-cloud-client-a
      label: master
      # 这种写法,当application.yml也设置了spring.profiles.active属性值时,该属性值会被替换,故实际获取的是application.yml中设置的active的值
      profile: ${spring.profiles.active}

application.yml配置文件:

# 若两者都设置了同样的属性值,那么application.yml里的会覆盖调bootstrap.yml里的内容,如下面的spring.application.name
server:
  port: 8763

spring:
  application:
    name: SpringCloud-ClientA

3)验证

启动Config配置中心项目和客户端项目,访问客户端配置的getA接口: http://localhost:8763/getA

获取到如下数据,说明客户端获取远程仓库数据成功:

{"name":"czm","age":22,"book":"hobby.book","anume":"hobby.anume","profile":"dev"}

4. 结合Eureka使用Config

按微服务架构来说,所有需要注入到Eureka服务端的都是Eureka的客户端,所有需要获取远程仓库的服务都是Config客户端,故可以说除了Eureka服务端和Config服务端外,绝大多数服务都既是Eureka客户端,又是Config客户端,故需要兼顾这两者的配置。

我们先看下Config服务端接口Eureka的使用:

1)Config服务端结合Eureka使用

application.yml新增Eureka的服务中心地址:

eureka:
  client:
    service-url:
      # 由于Eureka服务中心配置了Security账号密码,故所有需要注入到服务中心的客户端都要再URL中携带账号密码,如下
      defaultZone: http://admin:123456@localhost:8761/eureka/

启动类也新增@EnableDiscoveryClient/@EnableEurekaClient,表示这是一个Eureka客户端服务,如示例的SpringCloud-Config项目模块。

2)Config客户端结合Eureka使用

application.yml新增Eureka的服务中心地址:

eureka:
  client:
    service-url:
      # 由于Eureka服务中心配置了Security账号密码,故所有需要注入到服务中心的客户端都要再URL中携带账号密码,如下
      defaultZone: http://admin:123456@localhost:8761/eureka/

启动类也新增@EnableDiscoveryClient/@EnableEurekaClient,表示这是一个Eureka客户端服务,如示例的SpringCloud-ClientA项目模块。

三、SpringCloud OpenFeign

1. **负载均衡——**Spring Cloud Ribbon

负载均衡分了两种类型:

  • 客户端负载均衡(Ribbon)

    • 服务实例的清单在客户端,客户端进行负载均衡算法分配。
    • (从上面的知识我们已经知道了:客户端可以从Eureka Server中得到一份服务清单,在发送请求时通过负载均衡算法,在多个服务器之间选择一个进行访问)
  • 服务端负载均衡(Nginx)

    • 服务实例的清单在服务端,服务器进行负载均衡算法分配

2. **容错保护——**Spring Cloud Hystrix

Spring Cloud Hystrix实现了断路器线程隔离等一系列服务保护功能。

  • Fallback(失败快速返回):当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝), 向调用方返回一个错误响应, 而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
  • 资源/依赖隔离(线程池隔离):它会为每一个依赖服务创建一个独立的线程池,这样就算某个依赖服务出现延迟过高的情况,也只是对该依赖服务的调用产生影响, 而不会拖慢其他的依赖服务。

Hystrix提供几个熔断关键参数:滑动窗口大小(20)、 熔断器开关间隔(5s)、错误率(50%)

  • 每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。
  • 直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。

3. 服务调用——SpringCloud Feign/OpenFeign

Spring Cloud Feign基于 Netflix Feign 实现,整合了 Spring Cloud Ribbon 与 Spring Cloud Hystrix, 除了整合这两者的强大功能之外,它还提 供了声明式的服务调用(不再通过RestTemplate)。

Spring Cloud OpenFeign在Feign的基础上支持了SpringMVC的注解,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

1)新建项目

新建一个Eureka Client项目,加入openFeign依赖:


	org.springframework.cloud
	spring-cloud-starter-openfeign

2)配置

普通的Eureka Client配置

server:
  port: 8764
spring:
  application:
    name: service-openfeign
eureka:
  client:
    service-url:
      defaultZone: http://admin:123456@localhost:8761/eureka

注入Restemplate:

@Configuration
public class RestemplateConf {

    @Bean
    @LoadBalanced       // 开启负载均衡,URL使用服务名时必须加上此注解
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

3)测试

新建两个Eureka Client项目(git中的SpringCloud-Eureka-B和SpringCloud-Eureka-C项目),除了端口不一样后,其余部分都一样,都暴露出一个同样的接口,组成负载系统

yml配置如下:

server:
  port: 8765	# 端口不同,另一个是8766

spring:
  application:
    name: provider		#两个项目的服务名称必须一样

eureka:
  client:
    service-url:
      defaultZone: http://admin:123456@localhost:8761/eureka

暴露的接口,return的返回值有细微差别:

@RestController
@RequestMapping("/openFeign")
public class OpenFeignClientController {

    @GetMapping("/test")
    public Object openFeignTest() {
        return "Spring Cloud 服务提供者——B,端口:8765";
    }
}

OpenFeign 项目

添加OpenFeign接口:

@FeignClient("provider")    // Eureka中的服务名
public interface OpenFeign {

    @GetMapping("/opnefeign/test")  // 指定服务中的某一个接口,直接通过 FeignInterface.test() 调用该接口
    String openFeignTest();
}

PS:这里接口的返回值用的是String,如果改为Object会后面测试时报错:Could not extract response: no suitable HttpMessageConverter found for response type [class java.lang.Object] and content type [text/plain;charset=UTF-8]

具体原因还不清楚,如果有大佬知道还请不吝赐教!

添加OpenFeign测试接口:

@RestController
public class OpenFeignController {

    @Resource
    OpenFeign openFeign;

    @GetMapping("/test")
    public Object test() {
        return openFeign.openFeignTest();
    }
}

4)验证

依次启动Eureka服务端项目、两个Eureka Client项目(B和C),最后启动类上新增**@EnableFeignClients**注解(开启 feign 功能)启动OpenFeign项目,浏览器访问test接口:http://localhost:8764/test,不断刷新页面,会发现页面内容是8765端口和8766端口返回的内容,两者交替出现,这就实现了一个简单的负载均衡。

四、SpringCloud GateWay

1. GateWay简介

网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 网关这一层。也就是说,API 的实现方面更多地考虑业务逻辑,而安全、性能、监控可以交由 网关来做,这样既提高业务灵活性又不缺安全性。

优点:

  • 安全 ,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。

  • 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。

  • 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。

  • 减少了客户端与各个微服务之间的交互次数。

  • 易于统一授权。

2. 项目搭建

新建一个Eureka Client项目,pom中添加gateway依赖:


    org.springframework.cloud
    spring-cloud-starter-gateway

配置文件内容:

server:
  port: 8790
spring:
  application:
    name: service-gateway
  cloud:
    gateway:
      # 开启网关
      enabled: true
      discovery:
        locator:
          # 开启自动路由,以服务名建立路由
          enabled: true
          # 将服务名改为小写,否则url中指定服务名时必须大写
          lower-case-service-id: true
eureka:
  client:
    service-url:
      defaultZone: http://admin:123456@localhost:8761/eureka

3. 测试

通过网关访问服务接口URL的格式:http://网关地址:网关端口/服务名/服务对外提供的URL

启动Eureka服务中心,再任意启动一个Eureka客户端(这里我启动的是端口为8766的ClientC项目)和网关项目,分别访问http://localhost:8766/openFeign/test 和 http://localhost:8790/provider/openFeign/test,可以看的,两个页面显示的内容是一样的,说明实际访问的接口是一个接口。

Spring Cloud应用_第10张图片

Spring Cloud应用_第11张图片

你可能感兴趣的:(Spring,Boot,spring,cloud,eureka,java)