今天是:
带着程序的旅程,每一行代码都是你前进的一步,每个错误都是你成长的机会,最终,你将抵达你的目的地。
title

SpringCloud入门搭建

环境搭建

这里使用idea, gradle常见spring cloud 工程。

首先在idea中创建一个Gradle的空项目,作为父工程。

创建完项目后我们修改build.gradle配置文件,设置Springboot,SpringCloud版本,公用属性

buildscript {
    ext {
        springBootVersion = '2.3.7.RELEASE'
        springBootManagementVersion = '1.0.10.RELEASE'
        springCloudVersion = 'Hoxton.SR10'
    }
    repositories {
        mavenLocal() //1.优先查找本地maven库,性能最好
        maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
        mavenCentral()//3.最后查找maven中央库
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("io.spring.gradle:dependency-management-plugin:${springBootManagementVersion}")
    }
}

allprojects {
    group "com.zlennon"
    version "1.0.0"
}

subprojects {
    apply plugin: 'java'
    apply plugin: 'application'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11

    repositories {
        mavenLocal() //1.优先查找本地maven库,性能最好
        maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
        mavenCentral()//3.最后查找maven中央库
    }
    dependencies {
        testCompile(
                "org.springframework:spring-test",
                "junit:junit:4.12"
        )
    }
    dependencyManagement {
        imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") }
        imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" }
    }
}

完成之后我们可以执行gradle build 或在idea中执行构建。

既然是微服务,我们先创建一个简单的服务提供这和服务消费者。在父项目下创建模块covid-provider和covid-cosumer

将这两个模块加入到父工程当中

rootProject.name = 'springcloud'
include ':covid-consumer'
include ':covid-provider'

修改各个模块的application.yml配置文件

//消费者
server:
  port: 8081
  servlet:
    context-path: /
api:
  url:
    prefix : http://localhost:8080/api/covid/


//提供者
server:
  port: 8080
  servlet:
    context-path: /
  error:
    whitelabel:
      enabled : false

spring:
  application:
    name: ms-covid-provider-8080
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/springcloud?serverTimezone=UTC&useSSL=false
    username: root
    password: 123456
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

服务提供放创建响应的module,,service,repository,api访问接口供消费者调用

@RestController
@RequestMapping("/api/covid")
public class CovidController {

    @Autowired
    CovidService covidService;

   @GetMapping("/findAll")
    private List<Covid> findAll(){
        return  covidService.findAll();
    }

    @PostMapping("/saveDailyData")
    private void saveDailyData(){
       covidService.saveDailyData();
    }
}

消费者方

@RestController
@RequestMapping("/covid")
public class CovidController {

    @Autowired
    CovidService covidService;
    @Autowired
    RestTemplate restTemplate;
    @Value("${api.url.prefix}")
    String apiUrl;

   @GetMapping("/findAll")
    private List<Covid> findAll(){
       return Arrays.asList(restTemplate.getForObject(apiUrl+"findAll",Covid[].class)) ;
    }

    @PostMapping("/saveDailyData")
    private void saveDailyData(){
        restTemplate.postForEntity(apiUrl+"saveDailyData",null,String.class);
    }
}

启动两个springboot,使用消费者服务连接访问http://localhost:8080/covid/findAll。有了服务提供者我们就可以直接调用服务了,但是如果服务非常多的化,很难记住每个服务的ip和端口,也不知道每个服务是干什么的。这个时候就需要将服务统一注册管理,接下来将服务注册到Enreka服务注册中心。

服务注册

新创建服务注册模块 server-registry

导入依赖包 ` implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'`

配置Eureka服务注册中心

server:
  port: 9001
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

启动应用,访问http://localhost:9001/ ,看如如下界面Eureka已配置正确

将服务提供者注册到Eureka

引入依赖compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')

在启动类加注解

eureka:
  client: #客户端注册进eureka服务列表内
    service-url:
      defaultZone: http://localhost:9001/eureka/
  instance:
    instance-id: ms-cloud-covid-8080
    prefer-ip-address: true     #访问路径可以显示IP地址

在消费者方配置

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://localhost:9001/eureka/

当我们再次访问Eureka时,就会发现已注册的服务实例

使用Consul作为注册中心

需要的依赖implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery'

spring:
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ms-covid-provider-consul

启动注解类@EnableDiscoveryClient

既然服务已经注册到Eureka,就需要到服务中心去找对应的服务,怎么找到对应的服务呢,这个时候就需要Ribbon或Feign 闪亮登场了,Ribbon是一个客户端的负载均衡组件,Feign是一个声明式WebService客户端.

负载均衡查找服务

  • ribbon

引入ribbon依赖 

implementation 'org.springframework.cloud:spring-cloud-starter-netflix-ribbon'

由于掉远程服务使用的是rest 所以我们在RestTemplate加上配置,@LoadBalanced 通过负载均衡查找服务

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

将客户端调用的的服务连接改为Eureka中的服务连接

http://ms-covid-provider-8080/api/covid/

将客户端标记为RibbonClient

@RibbonClient("ms-covid-consumer-8081")

  • Feign

依赖 implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

申明接口

@RestController
@RequestMapping("/covid")
public class CovidController {

    @Autowired
    FeignClientService feignClientService;

   @GetMapping("/findAll")
    private List<Covid> findAll(){
       return feignClientService.findAll() ;
    }

    @PostMapping("/saveDailyData")
    private void saveDailyData(){
        feignClientService.saveDailyData();
    }
}


---------------------------------------------------------------------


@FeignClient(value = "ms-covid-provider-8080",path = "/api/covid")
public interface FeignClientService {

    @RequestMapping("/findAll")
    public List<Covid> findAll();

    @RequestMapping("/saveDailyData")
    public void saveDailyData();
}

启动类标记客户端@EnableFeignClients()。

Spring Cloud Hystrix熔断

在分布式系统中服务之间会存在级联调用,加入其中某些服务异常,将会使一条线上的调用超时或失败,进而可能造成请求的大量堆积。Hystrix通过添加延迟,容错,提供备选项 可以提高系统的整体弹性。

引入依赖 implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'

配置文件中 开启熔断

feign:
  hystrix:
    enabled: true

在主启动类添加  @EnableHystrix或@EnableCircuitBreaker注解

  • 使用@HystrixCommand

HystrixCommand 方式很简单,@HystrixCommand(fallbackMethod = "findCovidFail") ,添加注解并设置调用异常时的处理方法。若果方法较多的话这多处理方法非常繁琐。

  • 使用fallbackFactory

feigin申明式调用

@FeignClient(value = "ms-covid-provider-8080",path = "/api/covid",fallbackFactory=CovidFallbackFactory.class)
public interface FeignClientService {

	@RequestMapping("/findAll")
	public List<Covid> findAll();

	@RequestMapping("/findById/{id}")
	public Covid findById(@PathVariable(value="id") Integer id);
}

失败回调工厂

@Component
public class CovidFallbackFactory implements FallbackFactory<FeignClientService> {
    Logger logger = LoggerFactory.getLogger(getClass());
    @Override
    public FeignClientService create(Throwable cause) {
        return new FeignClientService() {
            @Override
            public List<Covid> findAll() {
                return Collections.emptyList();
            }

            @Override
            public Covid findById(Integer id) {
                logger.error(cause.toString());
                return new Covid();
            }

        };
    }
}

完成配置后我们启动服务测试,根据id查找不到数据的会抛异常,进而会调用我们出错情况下的处理方法。

Spring Cloud 网关

微服务部署以后,当请求当来后就可以提供服务了,但是这些请求中可能包含不正常的请求,或者请求不能找到正确的服务,就像每个组织机构一样,都会设置一个前台接待客人,前台人员可以带着你找到你组织其他部门不至于迷路。spring cloud gateway为我们提供了这样一套机制,实现请求的路由,转发,校验等。

创建一个spring boot gateway模块 

引入依赖

implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')

修改

server:
  port: 7002


spring:
  application:
    name: covid-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id:  covid-route #注意id前面的-需要
          uri: http://localhost:8080
          predicates:
            - Path=/api/covid/**

启动服务提供者8080,gateway  测试访问 http://localhost:7002/api/covid/findAll,可以访问,说明在访问/api/covid/**这样的路径是请求将被转发到8080上。

因为我们的服务都已经注册到了Eureka,那么就需要gateway到Eureka上找到请求对应的服务。  所以呢gateway应用也注册到Eureka中,这样gateway就能找到Eureka中的其他服务了。

完整的配置文件,同时启动类要标记为@EnableEurekaClient

server:
  port: 7002


spring:
  application:
    name: covid-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id:  covid-route
          uri: lb://ms-covid-provider-8080
          predicates:
            - Path=/api/covid/**

eureka:
  client: #客户端注册进eureka服务列表内
    service-url:
      defaultZone: http://localhost:9001/eureka/
  instance:
    instance-id: ms-cloud-gateway
    prefer-ip-address: true     #访问路径可以显示IP地址

访问http://localhost:7002/api/covid/findAll能够成功。

后台打印如下语句

DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client ms-covid-provider-8080 initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=ms-covid-provider-8080,current list of Servers=[192.168.3.4:8080],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;	Instance count:1;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]

说明通过负载均衡找到了配置的服务。好了我们最简单的微服务已经配置好了,准备部署上线了,但是可能代码中只配置了开发环境的配置,生产环境有一些密码什么的不希望让开发人员看到,如果要让运维人员手动去改,少了还好,几百个微服务就麻烦了,能把运维人员给累死。并且开发的过程想要修改配置文件需要重启应用。这个时候就需要SpringCould的分布式配置中心了。

Spring Cloud Config 分布式配置中心

Spring Cloud Config是通过git 管理的,所以我们需要在Github一个仓库存放配置信息。仓库创建好了之后,需要创建一个Spring Cloud 配置服务,用来连接github访问上面的配置信息。

导入需要的包 

implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'

配置git仓库信息 ,包含如下文件

server:
  port: 7003

spring:
  application:
    name: cloud-config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/lennonn/spring-cloud-config
          search-paths: /

使用@EnableConfigServer开启配置服务,启动访问我们的配置信息 http://localhost:7003/application-providerconfig.yml ,能访问到说明配置正确。

客户端需要获取配置中心的文件访问,所以需要配置客户端以找到配置文件,需要创建一个bootstrap.yml,并且需要引入依赖

implementation 'org.springframework.cloud:spring-cloud-starter-config'

spring:
  cloud:
    config:
      name: application-providerconfig #需要从github上读取的资源名称,注意没有yml后缀名
      profile: dev   #本次访问的配置项
      label: master   
      uri: http://localhost:7003
 

上面的配置说明我们的客户端去配置中心(http://localhost:7003)找一个文件名叫application-providerconfig.yml的文件

开启客户端,下面的输出证明已经拿到配置文件

09:42:19.682 [main] INFO  org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.getRemoteEnvironment - Fetching config from server at : http://localhost:7003
09:42:22.536 [main] INFO  org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.log - Located environment: name=application-providerconfig, profiles=[dev], label=master, version=40a4c183499f7a1ddf76ffb4758c1d33be5775e7, state=null

总结

在上面我们搭建了最简单的SpringCloud应用,使用了它的基本组件,每个组件都是单个服务的,这样的应用显然不具备高可用性,同时分为多个组件增加了系统复杂性,为了构建高可用的分布式应用,我们之后需要部署为集群方式。

分享到:

专栏

类型标签

网站访问总量