spring-cloud使用

发布于:2025-07-21 ⋅ 阅读:(15) ⋅ 点赞:(0)

nacos -注册中心

nacos是alibaba提供的管理微服务架构的注册中心,在上面可以管理你的每一个服务内容。

引入

前往官网下载zip或者通过docker引入,下载好之后通过cmd命令启动。位置在bin目录下。

startup.cmd -m standalone 

这个命令的意思是通过单体项目启动nacos注册中心,启动之后可以看到你的nacos生成网址。
在这里插入图片描述
然后我们就需要在自己的项目中进行配置了,主项目需要引入下面这个包

<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

让他们被发现nacos发现,然后在子model中,引入web包,让他们成为web服务。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

在子model中进行yml配置,通常nacos识别的服务名称就是你设置的applicationName。然后设置nacos服务地址为localhost:8848。

server:
  port: 8000
spring:
  application:
    name: service-order
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      config:
        import-check:
          enabled: false

这样你就可以在网址上看到你这个model的服务了。
在这里插入图片描述
之前必须要在启动类上加上注解@EnableDiscoveryClient才可以服务发现,但是从Spring Cloud Edgware开始,@EnableDiscoveryClient 或@EnableEurekaClient 可省略。只需加上相关依赖,并进行相应配置,即可将微服务注册到服务发现组件上。

使用代码获取每个服务信息

通过spring-cloud-nacos提供的discoveryClient接口来获取服务信息。

package com.atguigu.product;


import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.alibaba.nacos.api.exception.NacosException;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;

import java.util.List;

@SpringBootTest
public class DiscoveryTest {
    @Resource
    DiscoveryClient discoveryClient;

    @Test
    void discoveryTest(){
        discoveryClient.getServices().forEach(service->{
            List<ServiceInstance> instances = discoveryClient.getInstances(service);
            instances.forEach(serviceInstance -> {
                System.out.println("serviceInstance.getInstanceId() = " + serviceInstance.getInstanceId());
                System.out.println("serviceInstance.getHost() = " + serviceInstance.getHost());
                System.out.println("serviceInstance.getServiceId() = " + serviceInstance.getServiceId());
                System.out.println("serviceInstance.getPort() = " + serviceInstance.getPort());
            });
        });
    }
}

通过获取每个服务下的多个实例,并且将实例内容展示出来。
在这里插入图片描述

discoveryClient和nacosServiceDiscovery

就是spring和nacos提供的区别,如果使用的是前者discoveryClient,不管使用的是什么注册中心,都可以进行调用,而后者是引入nacos后才可以使用的接口。

   @Resource
    NacosServiceDiscovery nacosServiceDiscovery;

    @Test
    void discoveryTest() throws NacosException {
        nacosServiceDiscovery.getServices().forEach(service->{
            List<ServiceInstance> instances = null;
            try {
                instances = nacosServiceDiscovery.getInstances(service);
            } catch (NacosException e) {
                throw new RuntimeException(e);
            }
            instances.forEach(serviceInstance -> {
                System.out.println("serviceInstance.getInstanceId() = " + serviceInstance.getInstanceId());
                System.out.println("serviceInstance.getHost() = " + serviceInstance.getHost());
                System.out.println("serviceInstance.getServiceId() = " + serviceInstance.getServiceId());
                System.out.println("serviceInstance.getPort() = " + serviceInstance.getPort());
            });
        });
    }

一样的,具体我就不多写了。

nacos实现远程调用

当我们服务去访问另一个服务的时候,通过nacos可以实现,我们通过获得服务实例,可以以负载均衡的方式,然后通过springboot提供的http请求api进行访问,拿到数据后返回给服务即可。

下面是一个生成订单的服务,需要去远程获取到商品信息,就可以通过下列方式实现。

  package com.atguigu.order.service.impl;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;


import com.atguigu.order.bean.Order;
import com.atguigu.order.service.OrderService;
import com.atguigu.product.bean.Product;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;




@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    DiscoveryClient discoveryClient;

    @Resource
    RestTemplate restTemplate;

    @Override
    public Order createOrder(Long productId, Long userId) {
//        Product product = getProductFromRemoteWithLoadBalanceAnnotation(productId);
        //使用Feign完成远程调用
        Product product = getProFromRemote(productId);
        Order order = new Order();
        order.setId(1L);


        // 总金额
        order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));
        order.setUserId(userId);
        order.setNickName("zhangsan");
        order.setAddress("尚硅谷");
        //远程查询商品列表
        order.setProductList(Arrays.asList(product));



        return order;
    }

    private Product getProFromRemote(Long proId){
        List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
        ServiceInstance serviceInstance = instances.get(0);
        String uri="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/"+proId;
        log.info("远程调用:{}",uri);
        return restTemplate.getForObject(uri, Product.class);
    }

}

上面的写法全部是访问第一个服务实例,那我们如何使用负载均衡的方式进行获取服务实例呢?

负载均衡方式

首先需要引入spring-cloud为我们提供的实现负载均衡api

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

引入loadBalancerClient,使用方法choose即可实现负载均衡。

   @Autowired
    LoadBalancerClient loadBalancerClient;
    
private Product getProFromRemoteWithLoadBalance(Long proId){
        ServiceInstance serviceInstance = loadBalancerClient.choose("service-product");
        String uri="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/"+proId;
        log.info("远程调用以负载均衡的方式,实例为,{},uri:{}",serviceInstance.getInstanceId(),uri);
        return restTemplate.getForObject(uri, Product.class);
    }
通过注解方式实现负载均衡

使用 @LoadBalanced放到你要远程调用的实例上,然后通过将网址改成你要远程调用的实例就可以实现了。

   private Product getProFromRemoteWithLoadBalanceAnnoation(Long proId){
        String uri="http://servce-product/product/"+proId;
        log.info("远程调用以负载均衡的方式,uri:{}",uri);
        return restTemplate.getForObject(uri, Product.class);
    }
}

nacos-配置中心

nacos核心是什么,就是将各个分开的服务进行统一管理,配置中心就是将服务的配置进行统一管理。

首先要引入依赖

<!--配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency

然后在nacos中创建一个配置文件。
在这里插入图片描述
通过spring提供的外部配置文件绑定属性,来和nacos创建的文件进行绑定。

spring:
  application:
    name: service-order
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      config:
        import-check:
          enabled: false
  config:
    import: nacos:service-order.properties

然后就可以获取到里面内容并且进行操作了。


    @Value("${order.timeout}")
    private String timeout;

    @Value("${order.auto-confirm}")
    private String autoConfirm;

在这里插入图片描述
在这里有一点,如果你更改了nacos配置文件的内容,项目里并不会自动改变,只有重新启动或者配置了 @RefreshScope才可以刷新。
@RefreshScope写到使用配置文件内容的类上面

  @RefreshScope//自动刷新
@RestController
public class OrderController {


    @Autowired
    OrderService orderService;

    @Value("${order.timeout}")
    private String timeout;

    @Value("${order.auto-confirm}")
    private String autoConfirm;

    @GetMapping("/config")
    public String config(){
        return "autoConfirm = " + autoConfirm+",timeout="+timeout;
    }
}

也可以用**@ConfigurationProperties**,这个直接有自动刷新方式。

package com.atguigu.order.properties;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(prefix = "order")
@Data
public class OrderProperties {
    private String timeout;

    private String autoConfirm;
}

也是更推荐这种方式,解耦更好。

配置中心监听

我们可以通过下列代码实现监听

@Bean
    ApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager) {
        return (args) -> {
            ConfigService configService = nacosConfigManager.getConfigService();
            configService.addListener("service-order.properties",
                    "DEFAULT_GROUP", new Listener() {
                        //声明一个线程
                        @Override
                        public Executor getExecutor() {
                            return Executors.newFixedThreadPool(4);
                        }

                        @Override
                        public void receiveConfigInfo(String s) {
                            System.out.println("变化的配置信息:"+s);
                            System.out.println("邮件通知.........");
                        }
                    });
        };
    }

具体意思就是通过nacosConfigManager来获取配置服务类,通过配置服务类的添加监控方法,将需要监控的配置文件写到里面。

PS:配置中心的配置会覆盖本地配置,因为本地先配置中心后,不过为了统一配置,配置中心的配置应该才是优先级最高的配置。

配置中心-数据隔离

nacos可以通过设置命名空间来进行配置文件隔离。
在这里插入图片描述
设置完命名空间,你在创建配置文件的时候就可以把他们放到不同的 命名空间中,相当于一个文件夹,然后可以用配置文件的group来进行细分。
在这里插入图片描述
然后在项目yml中进行配置。

server:
  port: 8000
spring:
  application:
    name: service-order
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      config:
        namespace: a44d4fc8-aee8-4f5f-ab40-85a0db6d0998
        #这里的namespace写的是命名空间的id
  config:
    import:
      - nacos:common.properties?group=order
      - nacos:database.properties?group=order

要记住yml中配置的namespace是命名空间id,而不是名称。
在这里插入图片描述

OpenFeign

OpenFeign 是 Spring Cloud 生态中声明式的 HTTP 客户端框架,通过注解简化微服务间的远程调用‌。它基于原生 Feign 扩展,深度集成 SpringMVC 注解和负载均衡能力,使开发者能以调用本地方法的方式实现跨服务接口访问。‌‌‌‌
区别于编程式restTemplate,这个实现起来更加轻松。

使用

首先引入包


<!--        声明式远程调用-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

然后在启动类上**@EnableFeignClients**注解启动feign

@SpringBootApplication
@EnableFeignClients //启动feign
public class OrderMainApplication {

创建一个feign接口,并且实现远程调用api。

package com.atguigu.order.feign;

import com.atguigu.product.bean.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "service-product")
public interface ProductFeignClient {
    @GetMapping("/product/{id}")
    Product getOne(@PathVariable Long id);
}

spring会将带**@FeignClient的接口类里面的mvc格式接收头变为请求头,发送远程请求。
所以这个的意思就是去注册中心寻找
service-product**的服务,获取到他的url,并拼接param,获取内容返回给使用方。

第三方api

也可以通过feign实现第三方请求,区别于自己的服务,需要在注解上多增加一个url,来告诉spring,这个是外部请求。

package com.atguigu.order.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "service-weather",url = "http://t.weather.itboy.net/api/weather/city")
public interface WeatherFeignClient {
    @GetMapping("/{cityId}")
    public String weather(@PathVariable String cityId);
}

feign 日志

feign如果打开日志呢,只需要在配置类里面写上feignLogging的日志显示级别就行。


    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }

他还有NONE、BASIC、HEADERS。
分别是不显示内容。
显示请求方法和url和结果状态码和执行时间。
headers是显示basic的信息再加上request和response的headers。
full就是全有。

超时控制

如果feign请求的服务当机了,或者速度慢读取不到,我们都需要对feign进行一个超时控制。
对feign规定一个限时等待,如果超时就返回错误或者兜底数据,未超时就正常返回。
feign有一个默认设置。
在这里插入图片描述
连接时间10秒,等待时间60秒,那我们如何手动更改这些时间呢,其实就是更改options。

可以通过编码格式注入,也可以通过配置文件注入。

spring:
    openfeign:
      client:
        config:
          default:
            connect-timeout: 1000
            read-timeout: 2000
@Configuration
public class FeignConfiguration {

    @Bean
    public Request.Options options() {
        return new Request.Options(8, TimeUnit.SECONDS, 8, TimeUnit.SECONDS, true);
    }


但是一定是约定>配置>编码的,所以配置文件的优先级会更高一些。

拦截器

可以在feign上用拦截器加一层,请求拦截器和响应拦截器,用feign提供的RequestInterceptor就可以。

package com.atguigu.order.interceptor;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;

import java.util.UUID;
@Component
public class XTokenRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header("token", UUID.randomUUID().toString());
    }
}

那如何让spring知道这个拦截器呢,有两种方法,一种是直接将他放入容器中, feign每次都会从容器中读取requestInterceptor,或者使用配置文件。

 spring:
    openfeign:
      client:
        config:
          service-product:
            connect-timeout: 3000
            read-timeout: 3000
            request-interceptors:
              - com.atguigu.order.interceptor.XTokenRequestInterceptor
  

兜底回调

就是如果没有获得本身内容,不返回给用户错误,而是一些假数据,让程序可以继续进行下去,也可以让用户体验好一些,那应该如何操作呢。需要使用sentinel来进行操作。

sentinel

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。

使用

首先下载sentinel的jar包,并且启动。

java -jar sentinel.jar 

他默认占用8080端口,访问就可以看见sentinel的web页面。账号和密码都是sentinel
在这里插入图片描述
如何让服务放入到里面呢,就是引入依赖,并且配置文件配置就行了,具体如下。

<!--sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

application.yml

spring:   
    sentinel:
      transport:
        dashboard: localhost:8080 #面板位置
      eager: true #自动刷新

注入之后就可以看见他在里面显示出来了。

簇点链路

用户去访问资源的时候,如果这个资源配置了规则,sentinel就会去检查规则,如何符合则放行,如果不符合则抛出异常或者执行兜底回调。簇点链路就是sentinel在读取资源操作显示在页面上的链路操作,如下图。
在这里插入图片描述

下列配置就是将服务注册到sentinel中,可以被簇点链路获取。

spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true

eager是热加载,本身是要进行请求才会在sentinel中显示服务,将这个设置为true,可以直接出现。

异常处理

当我们给簇点链路设置规则之后,拦截的内容为sentinel为我们设定的,那我们如何自定义呢,这就要看我们如何设置得了。

根据下图,我们看到,如果是在浏览器端设置的,统一由BlockExceptionHandler来处理。
在这里插入图片描述
我们可以实现这个接口,自定义异常处理。
具体代码如下:

package com.atguigu.order.exception;

import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.common.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;

import java.io.PrintWriter;
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
    ObjectMapper objectMapper = new ObjectMapper();
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String s, BlockException e) throws Exception {
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter writer = httpServletResponse.getWriter();
        R r = R.error(500, s + "流量超载,原因是" + e.getCause().getMessage());
        String json = objectMapper.writeValueAsString(r);
        writer.write(json);
    }
}

@SentinelResource
一般是为非controller层设置的规则注解,设置之后可以被sentinel识别,继而可以配置规则,如果在这里出现规则限制,这去返回异常,异常可以被注解你的blockHandler包裹的方法解决,或者全局异常解决,具体如下。

    @SentinelResource(value = "createOrder",blockHandler = "orderFallback")
    public Order createOrder(Long productId, Long userId) {
//        Product product = getProductFromRemoteWithLoadBalanceAnnotation(productId);

        //使用Feign完成远程调用
        Product product = productFeignClient.getProductById(productId);
        Order order = new Order();
        order.setId(1L);


        // 总金额
        order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));
        order.setUserId(userId);
        order.setNickName("zhangsan");
        order.setAddress("尚硅谷");
        //远程查询商品列表
        order.setProductList(Arrays.asList(product));

        return order;
    }
   public Order orderFallback(Long productId, Long userId,BlockException e) {
        return new Order();
    }

剩下两个一个是openfeign远程调用,通过注解的fallback解决,一个是SphU,可以用来访问资源文件,通过try/cache解决。

规则-流浪控制

限制多余的请求,从而保护系统资源不被耗尽。
在这里插入图片描述

阙值类型

qps:统计每一秒的请求数
并发线程数:统计并发线程数
在这里插入图片描述
勾选是否集群,就可以选择单机阙值和总体阙值。
单机阙值就是每一个集群每秒可以访问的数量,总体阙值就是这几个集群一共可以访问的数量。

流控模式

流控模式可以选择3种模式,分别是直接、关联、链路。

直接策略就是上面的直接拦截,这里就不讲了。

链路策略:可以规定在在这个链路上的,访问量大的请求被拦截,就是更加灵活,不用直接拦截,只拦截请求量这个链路上请求量大的了。

关联策略:就是可以绑定另一个请求,当你在访问本请求时候,可以关联让另一个请求被拦截,这种可以用在数据校准度比较高的时候,在更改访问量大的时候,让访问的人少一些。

流控效果

流控效果有3个,快速失败、warm up、排队等待。

快速失败:就是当访问量超过阈值的时候,直接拦截失败。

warmup:我称之为慢慢起床,就是假如有10个请求,我们先走3个,过一会儿再走剩下的,这个数量是逐步递增的。

排队等待:就是字面意思,大家都排队,每次进来几个,然后有一个timeout,如果过了,剩下排队的请求都挂掉了。

sentinel具体内容可以查看官方文档

gateway

gateway,相当于统一管理的后端的入口,你可以在后端入口进行拦截、保护、过滤等等请求。

使用

首先,使用gateway要引入依赖。

 <dependencies>
        <!--网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--服务发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
                <!--负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
    </dependencies>

将gateway注册到nacos服务中,配置文件中进行nacos的配置。
然后在配置文件中,可以直接进行路由的配置。

server:
  port: 80
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: order-route
          uri: lb://service-order
          predicates:
            - Path=/api/order/**
        - id: product-route
          uri: lb://service-product
          predicates:
            - Path=/api/product/**

gateway默认优先级是顺序排列,如果你在第一个设置了非常大范围的Path,那么下面的内容就不会显示,可以使用order解决

    gateway:
      routes:
        - id: order-bing
          uri: https://cn.bing.com/
          predicates:
           - Path=/**
          order: 10

predicates

断言,给路径可以设置规则。

predicates参数

在这里插入图片描述

自定义断言

如果我们想自定义断言,那应该如何进行呢。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.cloud.gateway.handler.predicate;

import jakarta.validation.constraints.NotEmpty;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

public class QueryRoutePredicateFactory extends AbstractRoutePredicateFactory<Config> {
    public static final String PARAM_KEY = "param";
    public static final String REGEXP_KEY = "regexp";

    public QueryRoutePredicateFactory() {
        super(Config.class);
    }

    public List<String> shortcutFieldOrder() {
        return Arrays.asList("param", "regexp");
    }

    public Predicate<ServerWebExchange> apply(final Config config) {
        return new GatewayPredicate() {
            public boolean test(ServerWebExchange exchange) {
                if (!StringUtils.hasText(config.regexp)) {
                    return exchange.getRequest().getQueryParams().containsKey(config.param);
                } else {
                    List<String> values = (List)exchange.getRequest().getQueryParams().get(config.param);
                    if (values == null) {
                        return false;
                    } else {
                        for(String value : values) {
                            if (value != null && value.matches(config.regexp)) {
                                return true;
                            }
                        }

                        return false;
                    }
                }
            }

            public Object getConfig() {
                return config;
            }

            public String toString() {
                return String.format("Query: param=%s regexp=%s", config.getParam(), config.getRegexp());
            }
        };
    }

    @Validated
    public static class Config {
        private @NotEmpty String param;
        private String regexp;

        public String getParam() {
            return this.param;
        }

        public Config setParam(String param) {
            this.param = param;
            return this;
        }

        public String getRegexp() {
            return this.regexp;
        }

        public Config setRegexp(String regexp) {
            this.regexp = regexp;
            return this;
        }
    }
}

filter

过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。过滤器可以限定作用在某些特定请求路径上。 Spring Cloud Gateway包含许多内置的GatewayFilter工厂。

GatewayFilter工厂同上一篇介绍的Predicate工厂类似,都是在配置文件application.yml中配置,遵循了约定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名称,而不需要写全部的类名,比如AddRequestHeaderGatewayFilterFactory只需要在配置文件中写AddRequestHeader,而不是全部类名。在配置文件中配置的GatewayFilter Factory最终都会相应的过滤器工厂类处理。

server:
  port: 8081
spring:
  profiles:
    active: add_request_header_route

---
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: http://httpbin.org:80/get
        filters:
        - AddRequestHeader=X-Request-Foo, Bar
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  profiles: add_request_header_route


cors

跨域问题可以通过gateway来解决

spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allow-credentials: true
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"

也可以通过meta进行单个的配置,不过一般不需要。

seata

分布式事务,用来解决分布式服务出现的数据不一致问题。

本身的服务是各自操作各自的,但我们在一个服务中通过openFeign去访问另一个服务的操作,并不会被本地的事务回滚。

seata拥有三个对象
1.TC transaction coordinator 事务协调者
2.TM transaction manager 事务管理器 全局事务
3.RM Resource manager 资源管理器

在这里插入图片描述
也就是当business开始这个服务的事务,会首先通知tc,tc给予一个全局事务,business去rpc访问其他服务,其他服务会创建分支事务,并且告诉tc,tc会知道所有服务的状态。

使用

首先安装seata

<dependency>
 <groupId>com.alibaba.cloud</groupId>
 <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

使用注解**@GlobalTransaction**

seata使用二阶提交方式,首先每个服务先在本地进行操作,并且向tc申请全局锁,并且将前镜像和后镜像存储到undo_log当中,并将结果返回给tc。
第二阶段,tc根据返回的结果来进行回滚,回滚通过undo_log存储的数据,恢复到前镜像,并且这时候还会判断目前数据库的内容是否跟后镜像一样。

seata 四种事务模式

auto模式,全程有seata控制,从主事务到分支事务。
ax:全局锁是互斥锁。
tcc:具体实现要由程序员实现,prepare、commit、rollback
saga:结合消息队列,就是执行完成后,会通知下一个服务。

这就是基本使用的cloud了,完事。


网站公告

今日签到

点亮在社区的每一天
去签到