SpringCloud 配置

529 阅读7分钟

版本相关

与Springboot对应版本

中央仓库找对应版本

版本变动

因netflix相关组件不再维护,2020版本移除了netflix相关组件,下面不再维护的建议只在2020版本前使用

版本管理依赖

由版本管理依赖管理SpringCloud组件版本,不需要手动配置

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

注册中心

Eureka

配置

用户端依赖

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

用户端注解
@EnableEurekaClient

服务端依赖

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

服务端注解
@EnableEurekaServer

常用配置文件

server:
  port: 9000
Spring:
  application:
    name: Eureka1
eureka:
  client:
    fetch-registry: false  #是否从注册中心获取注册信息(服务端填false,客户端选填)
    register-with-eureka: false  # 是否向注册中心注册(服务端填false,客户端选填)
  #  enabled: true #是否启用客户端
    service-url:
      defaultZone: http://server1:9000/eureka/ #指定注册中心地址,多个用逗号分割(服务端单例填自己,集群填其他服务端)
    registry-fetch-interval-seconds: 30 #多少秒从注册中心拉一次服务列表
  server:
  #  renewal-percent-threshold: 0.85 # 85%客户端无法连接时开启自我保护,不改动服务列表
  #  enable-self-preservation: false #是否开启自我保护()
  instance:
    prefer-ip-address: true #是否优先用ip地址作为主机名标识
    appname: name # 服务名,未配置则用spring.application.name 都没配就是unknown
  #  lease-expiration-duration-in-seconds: 90 #指定服务端可接受最长时间无心跳客户端连接
  #  lease-renewal-interval-in-seconds: 5 #指定客户端发送心跳时间
  #  hostname: localhost # 主机名称,不配置时用操作系统主机名

声明式调用客户端Feign

Maven配置

Maven 2020版本以前 默认集成了

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

2020版本移除了Hystrix和Ribbon,需要使用新依赖支持负载均衡loadbalancer

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>

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

使用

使用实例 http://t.csdn.cn/MBsUL

启动类上加@EnableFeignClients
调用Eureka客户端“服务ID”暴露的“/test”接口,会生成代理Bean,对父接口方法也生效,可用于公共模块

@FeignClient(name = "服务ID")
public interface Service  {
    @GetMapping("/test")
    public String test(@RequestParam("name") String name);
    
}

Yml配置

feign:
  client:
    config:
  hystrix:
    enabled: true  #开启Feign的熔断功能 2020版本失效
  compression:
    request:
      enabled:
  okhttp:
    enabled: 
  httpclient:
    enabled: true 

负载均衡

Ribbon(不再维护)

配置

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
ribbon: # 对所有服务生效
  eureka:
    enabled: true
  NFLoadBalancerRuleClassName: 负载均衡策略类
  ConnectTimeout: 5000 #连接超时时间,默认1s(1000)
  ReadTimeout: 5000     #读取超时时间
  OkToRetryOnAllOperations: true #对所有操作请求都进行重试
  MaxAutoRetries: 1  #对当前实例的重试次数
  MaxAutoRetriesNextServer: 2  #切换实例的重试次数
  
serviceID: # 对某个服务生效
  ribbon:
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
    return restTemplateBuilder.build();
}

使用返回的RestTemplate Bean会负载均衡

使用实例

负载均衡策略使用实例

负载均衡策略配置 http://t.csdn.cn/Cahhq

熔断/降级

Hystrix(不再维护)

在客户端熔断

配置

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

降级

启动类加@EnableHystrix API方法上使用

@Service
public class LocalItemService {
    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "hiError")
    public String hi(String id) {
        return restTemplate.getForObject("http://hystrix-provider/hi?id=" + id, String.class);
    }

    public String hiError(String id) {
        return String.format("Hi,your message is : %s but  request bad.", id);
    }
}

服务端不可用时会触发fallbackMethod方法

客户端降级

feign: 
  hystrix:
    enabled: true  #开启Feign的熔断功能 2020版本失效

Feign调用

@FeignClient(value = "hystrix-provider", configuration = HystrixConfig.class, fallback = LocalItemServiceImpl.class)
public interface LocalItemService{
    @RequestMapping(value = "/hi", method = RequestMethod.GET)
   public String hi(@RequestParam(value = "id")String id);

}
@Configuration
public class HystrixConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

熔断触发调用类

@Component
public class LocalItemServiceImpl implements LocalItemService{
    @Override
     public String hi(String id) {
               return String.format("Hi,your message is : %s but request bad.",id);
      }
}

网关

Zuul(不再维护)

默认支持ribbon和hystrix,建议在2020版本前使用

配置

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

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
zuul:
  routes:
    consumer-prod:
      path: /consumer-prod/**   # * 匹配任意数量字符 , ? 匹配任意单个字符 、 ** 匹配任意数量目录
      serviceId: consumer-prod  # 将所有/consumer-prod 请求转到consumer-prod
    service2:
      path: /service2/**   #默认为service2与所有服务创建映射
  host:
    connect-timeout-millis: 200000
    socket-timeout-millis: 200000
  ignored-services: '*' #忽略服务,可被上面覆盖,可用于关闭默认映射规则
  prefix: "/pre" # 前缀
  strip-prefix: true #否在转发前从路径中删除前缀

熔断

默认集成Hystrix

@Component
public class MyFallbackProvider implements FallbackProvider {
    @Override
    public String getRoute() {
        return "eureka-consumer";//对eureka-consumer服务开启熔断,返回*则对所有服务开启
    }
    @Override
    public ClientHttpResponse fallbackResponse(String route,
                                               Throwable cause) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }
            @Override
            public int getRawStatusCode() throws IOException {
                return this.getStatusCode().value();
            }
            @Override
            public String getStatusText() throws IOException {
                return this.getStatusCode().getReasonPhrase();
            }
            @Override
            public void close() {
            }
            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("连接异常,I'm the fallback".getBytes());
            }
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                MediaType mt = new MediaType("application", "json",
                        Charset.forName("UTF-8"));
                headers.setContentType(mt);
                return headers;
            }
        };
    }
}

过滤器

zuul定义了四种过滤器

  1. pre 请求被路由之前调用
  2. route 负责把请求转发到服务
  3. error 请求发送错误时调用
  4. post 在route和error过滤器之后调用
@Component
public class PreRequestLogFilter extends ZuulFilter {
    private static final Logger logger =  LoggerFactory.getLogger(
            PreRequestLogFilter.class);
    @Override
    public String filterType(){
        return "pre"; 
    }

    @Override
    public int filterOrder() {
        return 1;
    }
    @Override
    public boolean shouldFilter(){
        return true;
    }
    @Override
    public Object run(){
            //获取当前请求上下文
            RequestContext ctx = RequestContext.getCurrentContext();
            //取出当前请求
            HttpServletRequest request = ctx.getRequest();
            logger.info("进入访问过滤器,访问的url:{},访问的方法:{}",request.getRequestURL(),request.getMethod());
            //从headers中取出key为accessToken值
            String accessToken = request.getHeader("accessToken");//这里我把token写进headers中了
            //这里简单校验下如果headers中没有这个accessToken或者该值为空的情况
            //那么就拦截不入放行,返回401状态码
            if(StringUtils.isEmpty(accessToken)) {
                logger.info("当前请求没有accessToken");
                //使用Zuul来过滤这次请求
                ctx.setSendZuulResponse(false);
                ctx.setResponseStatusCode(401);
                return null;
            }
            logger.info("请求通过过滤器");
            return null;
        }

    }

Gateway

配置

相关资料

http://t.csdn.cn/4bDL4

使用Gateway时不能同时使用spring-boot-starter-web<依赖

<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-gateway</artifactId>
</dependency>
spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true    # 默认为false,设置为true表明spring cloud gateway开启服务发现和路由的功能,网关自动根据注册中心的服务名为每个服务创建一个router,将以服务名开头的请求路径转发到对应的服务
          lower-case-service-id: true     #启动 locator.enabled=true 自动路由时,路由的路径默认会使用大写ID,若想要使用小写ID,可将lowerCaseServiceId设置为true
      routes:  #路由
        # 路由id,可以随意写,唯一即可
        - id: user-service-route
          # 代理的服务地址;lb表示通过负载均衡从eureka中通过服务id获取具体服务
          uri: lb://consumer-user
        # 路由断言,可以配置映射路径
          predicates: #断言
            - Path=/consumer-user
          filters: #当前路由下的局部过滤器
           # 添加请求路径的前缀
      #    - PrefixPath=/user
      default-filters:  #全局过滤器
       # -

自定义过滤器/异常处理

Gateway有预设过滤器,也可以自定义过滤器
自定义过滤器看这篇博客Spring Cloud Gateway 服务网关的部署与使用详细介绍_gateway网关_张维鹏的博客,没了看上面相关资料

配置中心

SpringCloudConfig

配置实例

实例

http://t.csdn.cn/zQcTJ

服务端配置

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

启动类加@EnableConfigServer

读取配置方式

  1. 从本地读取
spring:
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/shared/ # 配置文件所在目录 配置文件名称格式为 服务ID-profile.yml  例如consumer-user-dev.yml
  1. 从远程Git仓库读取
spring:
  cloud:
    config:
      server:
        git:
          username: username    #用户名
          password: password #密码
          uri: 远程仓库地址 #要读取的远程仓库的配置文件的地址
          search-paths: cong #远程仓库文件夹地址
          default-label: master # 指定分支,不指定则默认master

用户端配置

<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-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

配置文件要写在bootstrap.yml文件中

spring:
  cloud:
    config:
      discovery:
        service-id: 注册中心服务ID  #注册中心服务ID
        enabled: true #开启客户端
    #  label: master # 指定分支,不指定则使用默认分支
      name: service1 # 指定应用名称,(默认服务id?没试过)    寻找name-profile.yml文件 本例中寻找 service1-dev.yml
      profile: dev # 指定激活环境,默认default   寻找name-profile.yml文件 本例中寻找 service1-dev.yml

动态刷新

实例

http://t.csdn.cn/Qelxr

所有服务实例加

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

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.4.3</version>
</dependency>

配置中心和(配置中心存储的客户端配置文件或客户端配置文件)配置rabbitmq地址

spring:
  rabbitmq:
    host: 主机地址
    port:
    username:
    password:

如果RabbitMQ配置在配置中心,客户端配置

spring:
  cloud:
    config:
      fail-fast: true #允许拉取配置文件前无法连接RabbitMQ

需要动态刷新的类上加@RefreshScope