Spring-Cloud Note


组件

  • Eureka
  • Ribbon
  • Feign
  • Hystrix
  • Zuul

@SpringCloudApplication注解

一个Spring Cloud标准应用包含服务发现以及断路器

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
  • @SpringCloudApplication
    • @SpringBootApplication
    • @EnableDiscoveryClient
    • @EnableCircuitBreaker

常用服务配置

spring:
  application:
    name: client                                #服务名称
server:
  port: 9070                                    #启动端口
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9090/eureka #定义服务注册中心地址

Eureka-服务注册/发现

配置

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

入口

package com.github.crazyjay97.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;


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

服务发现客户端可以在入口处加@EnableDiscoveryClient注解
可以打开 链接访问eurekaUI界面

接口服务

配置

server:
  port: 9080

spring:
  application:
    name: api

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9090/eureka

入口

package com.github.crazyjay97.api;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class ApiApplication {

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

接口控制器

package com.github.crazyjay97.api.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@RestController
public class Controller {

    @RequestMapping("hello")
    public String Hello() {
        System.out.println("请求处理");
        try {
            // 模拟任务处理,以及为熔断器做准备
            TimeUnit.SECONDS.sleep(new Random().nextInt(3));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "word";
    }
}

起多个api服务为负载均衡做测试,可以在启动时加-Dserver.port=9081参数指定端口

ribbon-客户端负载均衡

配置

spring:
  application:
    name: client

server:
  port: 9000

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9090/eureka
package com.github.crazyjay97.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class ClientApplication {


    @Bean
    @LoadBalanced  //加载 restTemplate Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

}

调用接口

package com.github.crazyjay97.client.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("client")
public class Controller {

    @Autowired
    private RestTemplate restTemplate;


    @RequestMapping("hello")
    public String hello() {
        //API 接口服务的名称,在eureka中以大写显示,这里写成大写
        String body = restTemplate.getForEntity("http://API/hello", String.class).getBody();
        return "hello" + body;
    }
}

hystrix-断路器

配置

spring:
  application:
    name: client

server:
  port: 9000

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9090/eureka

入口

package com.github.crazyjay97.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ClientApplication {


    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

}

服务

package com.github.crazyjay97.client.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("client")
public class Controller {

    @Autowired
    private RestTemplate restTemplate;


    @RequestMapping("hello")
    @HystrixCommand(fallbackMethod = "errorFallback")
    public String hello() {
        String body = restTemplate.getForEntity("http://API/hello", String.class).getBody();
        return "hello" + body;
    }

    public String errorFallback() {
        return "error";
    }
}

可以关掉一个api服务然后请求在不加断路器的情况下请求接口,当请求到已经关闭的api服务时,会出现500错误,当加断路器以后会出现处理之后的接口。当服务不可达、超时或故障的时候,触发断路器fallback方法。

feign-声明式调用

配置

spring:
  application:
    name: feign-client
server:
  port: 9070
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9090/eureka

入口

package com.github.crazyjay97.feignclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients //需要开启feign
@EnableCircuitBreaker
public class FeignclientApplication {

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

}

定义接口

package com.github.crazyjay97.feignclient.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("api") //接口服务的名称
public interface ApiService {

    @RequestMapping("/hello")
    String hello();
}

服务

package com.github.crazyjay97.feignclient.controller;

import com.github.crazyjay97.feignclient.service.ApiService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {

    @Autowired
    private ApiService apiService;

    @RequestMapping("hello")
    @HystrixCommand(fallbackMethod ="helloFallback")
    public String hello() {
        return "hello " + apiService.hello();
    }

    public String helloFallback() {
        return "error";
    }
}

zuul-网关服务

配置

zuul:
  routes:
    api-a-url:                      #自定义名称
      path: /api/**                 #前缀
      url: http://localhost:9070/   #转发的地址

入口

package com.github.crazyjay97;


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

@SpringBootApplication
@EnableZuulProxy
public class GatewayApplication {

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

config-配置中心

配置

spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/crazyjay97/cloud.git #仓库地址
          searchPaths: config                          #文件于仓库路径
          username: root
          password: root
server:
  port: 9050

依赖


    
        org.springframework.cloud
        spring-cloud-config-server
        2.2.1.RELEASE
    

入口

package com.github.crazyjay97;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {

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

配置中心客户端

配置-bootstrap.yml

spring:
  application:
    name: config-client
  cloud:
    config:
      profile: base
      label: master
      uri: http://localhost:9050
server:
  port: 9040

依赖


    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.cloud
        spring-cloud-starter-config
        2.2.1.RELEASE
    

入口

package com.github.crazyjay97;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConfigClientApplication {

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

控制器

package com.github.crazyjay97.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {

    @Value("${cloud-version}")
    private String version;

    @Autowired
    private Environment environment;

    @GetMapping("getConfig")
    public String getConfig() {
        return version + "-" + environment.getProperty("cloud-version");
    }
}