Spring Cloud 常用技术

1、服务注册与发现(Nacos)

  • 导入依赖

    <!-- Nacos 整合 SpringCloud-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

  • 修改配置文件

    spring:
        application:
            name: order-service  #服务名称   注册到注册中心的服务名称
        cloud:
            nacos:
                discovery:
                    server-addr: localhost:8848 #注册与发现中心地址
    ​

  • 启动Nacos 重启服务 检查Nacos控制台的服务管理·服务列表

2、远程调用(OpenFeign)

  • 服务必须已注册到Nacos控制平台

  • 服务消费方 导入依赖

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

  • 服务提供方 提供接口

    @RestController
    @RequestMapping("/storage")
    public class StorageController {
    ​
        @Autowired
        StorageService storageService;
    ​
        /**
         * 库存扣减接口 post /storage/deduct
         */
        @PostMapping("/deduct")
        public ResultVO<Object> deduct(@RequestParam String commodityCode, int count) {
            storageService.deduct(commodityCode, count);
            return ResultVO.success();
        }
    ​
        /**
         * post + json
         */
        @PostMapping("/json")
        public ResultVO<Object> deductJson(@RequestBody Storage storage) {
            storageService.deduct(storage.getCommodityCode(), storage.getCount());
            return ResultVO.success();
        }
    ​
        @GetMapping("/{code}")
        public ResultVO<Storage> getStorage(@PathVariable String code) {
            Storage storage = storageService.getStorage(code);
            return ResultVO.success(storage);
        }
    ​
        @PutMapping("/{id}")
        public ResultVO<Storage> update(@PathVariable int id, @RequestBody Storage storage) {
            return ResultVO.success();
        }
    ​
    }
    ​
     
  • 服务消费方 声明远程服务接口

    /*
     * 远程服务接口
     * 接口地址: http://storage-service/storage/deduct
     *
     * @FeignClient(name = "要调用的服务spring.application.name的值" )
     */
    @FeignClient(name = "storage-service")
    public interface StorageService {
    ​
       /**
        * post/put/get/delete + form
        * 1、参数是基本数据类型及其包装类、String:必须在所有的参数前必须加上@RequestParam
        * 2、参数是Java Bean: 必须在Java Bean前增加 @SpringQueryMap
        */
       @PostMapping("/storage/deduct")
       ResultVO<Object> deduct(@RequestParam String commodityCode, @RequestParam int count);
       // ResultVO<Object> deduct2(@SpringQueryMap Storage storage);
       
       /**
        * post/put/delete + json
        * 发送JSON的请求, 几乎不需要修改
        */
       @PostMapping("/storage/json")
       ResultVO<Object> deductJson(@RequestBody Storage storage);
       // ResultVO<Object> deductJson(@RequestBody Order order);
    ​
       @GetMapping("/storage/{code}")
       ResultVO<Storage> getStorage(@PathVariable String code);
    ​
       @GetMapping("/storage/{id}")
       ResultVO<Storage> update(@PathVariable int id, @RequestBody Storage storage);
    }

  • 在启动类上增加注解:,为远程服务接口创建代理对象

    @SpringBootApplication
    @MapperScan(basePackages = "com.exec.**.mapper")
    @EnableTransactionManagement
    // @EnableFeignClients(basePackages = "com.exec.**.api")
    @EnableFeignClients
    public class OrderApplication {
    ​
       public static void main(String[] args) {
          SpringApplication.run(OrderApplication.class, args);
       }
    }

  • 使用远程服务接口

    @Service
    public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
        
        //注入远程服务接口
        @Autowired
        StorageService storageService;
    ​
        /** 创建订单 */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void createOrder(Order order) {
            //  扣减库存
            ResultVO<Object> resultVO = storageService.deduct(order.getCommodityCode(), order.getCount());
            System.out.println(resultVO);
            save(order);
        }
    }

3、负载均衡(loadbalancer)

  • 导入依赖

    <!-- 负载均衡组件 -->
    <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>

  • 只要导入依赖,负载均衡自动实现,默认是 轮询

4、配置中心(Nacos)

在系统开发过程中,开发者通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的 是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。

配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成。配置变更是调整系统运行时行为的有效手段。

1. 核心概念

  • 一个具体的可配置的参数与其值域,通常以 key=value 的形式存在。

    • 例如:配置系统的日志输出级别logLevel=INFO|WARN|ERROR ) 就是一个配置项。

  • 一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件(如application.yml)通常就是一个配置集,包含了系统各 个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。

  • 配置集 ID 是组织划分配置的维度之一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配 置集都可以被一个有意义的名称标识。Data ID 通常采用类 Java 包(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一 性,此命名规则非强制。

  • Nacos 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 Buy 或 Trade )对配置集进行分组,从而区分 Dat a ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置 和 MQ_topic 配置。

  • 在 Nacos Spring Cloud 中, dataId 的完整格式如下

     ${prefix}-${spring.profiles.active}.${file-extension}
    • ${prefix}

      • 默认值:spring.application.name 的值

      • 如何修改:spring.cloud.nacos.config.prefix = ${spring.application.name}

    • ${spring.profiles.active}

      • 默认值:没有默认值

      • 如何修改:spring.profiles.active = dev

    • ${file-extension}

      • 默认值:properties

      • 如何修改:spring.cloud.nacos.config.file-extension = properties

2. 使用配置中心

bootstrap配置文件,一般添加 nacos配置中心的相关信息。项目的信息还是放到 application配置文件中。

注意:必须使用 bootstrap.properties或者 bootstrap.yaml配置文件来配置 Nacos Server 地址。‘

  • 导入依赖

    <!-- spring-boot-starter-web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- 注册与发现中心 spring-cloud-starter-alibaba-nacos-discovery -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
    <!--===== Nacos配置中心 + bootstrap start =====-->
    <!-- 配置中心 spring-cloud-starter-alibaba-nacos-config -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    
    <!-- bootstrap.yml | bootstrap.properties || spring-cloud-starter-bootstrap -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bootstrap</artifactId>
    </dependency>
    <!--===== Nacos配置中心 + bootstrap end =====-->

  • 编写bootstrap.yml文件

    server:
      port: 9003
    
    spring:
      application:
        # 服务名称(注册到Nacos中的服务的名称)
        name: config-service
    
      profiles:
        active: dev
    
      cloud:
        nacos:
          # 注册与发现中心地址
          discovery:
            server-addr: localhost:8848
          # 配置中心
          config:
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            # prefix可以省略, 它的默认值就是 spring.application.name 的值
            prefix: ${spring.application.name}
            # 默认值是properties
            file-extension: yml

  • 创建启动类

  • 在Nacos配置中心创建Data ID

    全部采用默认值:

    1、Data ID:config-serivce(这个就是spring.application.name的值)内容格式是 properties 格式

    2、Data ID:config-service.properties

仅增加 spring.profiles.active = dev 配置项

1、Data ID:config-serivce(这个就是spring.application.name的值)内容格式是 properties 格式

2、Data ID:config-service.properties

3、Data ID:config-service-dev.properties

修改 file-extension 的值

1、Data ID:config-serivce(这个就是spring.application.name的值)内容格式是 yaml 的格式

2、Data ID:config-service.yml

3、Data ID:config-service-dev.yml

配置优先级

3. Nacos配置持久化

Nacos 默认使用内置数据库 Apache Derby 数据库保存配置中心数据

将Nacos 配置中心使用的数据库切换为外部数据库 - MySQL

  1. 数据库

  1. 在数据库中创建表: 导入 nacos/conf/mysql-schema.sql 文件

  1. 修改Nacos配置

    修改nacos/conf/application.properties

    #*************** Config Module Related Configurations ***************#
    ### If use MySQL as datasource:
    ### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
    # spring.datasource.platform=mysql
    spring.sql.init.platform=mysql
    
    ### Count of DB:
    db.num=1
    
    ### Connect URL of DB:
    db.url.0=jdbc:mysql://127.0.0.1:3306/et2402_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
    db.user.0=root
    db.password.0=root

  2. 重启Nacos

4. 动态加载配置中心的配置项

  1. 使用 @Value 获取配置项:在当前Spring Bean对象上使用@RefreshScope

@RestController
// 自动刷新使用@Value获取的配置项
@RefreshScope
public class TestController {

   @Value("${user.id}")
   private int id;

   @Value("${user.name}")
   private String username;

   @RequestMapping("/test")
   public ResultVO<Object> test() {
      Map<Object, Object> userMap = MapUtil.builder()
         .put("id", id)
         .put("name", username)
         .build();
      return ResultVO.success(userMap);
   }
}
  1. 使用@ConfigurationProperties 获取配置项:可以自动刷新配置

@Data
@Component
// 读取 配置中心 或 本地配置文件中的以user开头的配置项
@ConfigurationProperties(prefix = "user")
public class UserProperties {

   /** 成员变量名称就是二级配置项 */
   private int id;

   /** 成员变量名称就是二级配置项 */
   private String name;
}

5、网关(gateway)

1. 网关介绍

网关(Gateway)组件是指用于构建具有统一入口的微服务架构中的一个组件,它可以实现动态路由、负载均衡、熔断、安全控制等功能。它的目标是为微服务架构提供⼀种简单、有效的、统⼀的API路由管理方式,且基于 Filter 链的方式提供了网关基本的功能,例如:安全、限流、熔断、路径重写、日志监控等功能。在微服务架构中,每个服务都有自己的入口,客户端需要知道每个服务的地址和端口号才能访问它们。而网关组件可以为所有服务提供一个统一的入口,客户端只需要知道网关的地址和端口号,就可以通过网关访问所有的服务。

三大核心概念

  1. 路由(route):路由是网关最基础的部分,路由信息由一个ID,一个目的URL、一组断言工厂和一 组Filter组成。如果断言为真,则说明请求URL和配置的路由匹配。

  2. 断言(Predicate):Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是 Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配 来自http Request中的任何信息,比如请求头和参数等。

  3. 过滤器(Filter):一个标准的Spring WebFilter,Spring Cloud Gateway中的Filter分为两种类型: Gateway Filter和Global Filter。过滤器Filter可以对请求和响应进行处理

2. 网关使用并实现负载均衡

  • 创建网关:gateway-01,配置Maven依赖

<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>
  • 编写配置文件:application.yml

server:
  port: 9006

spring:
  application:
    name: gateway03
    
    profiles:
    active: dev

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      
   	gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/order-system/**
          filters:
            - StripPrefix=1

        - id: storage-service
          uri: lb://storage-service
          predicates:
            - Path=/storage-system/**
          filters:
            - StripPrefix=1

3. 将路由配置放到 Nacos 配置中心

  • 导入依赖

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

   <!-- Nacos注册与发现中心 -->
   <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
   </dependency>

   <!-- 配置中心 -->
   <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
   </dependency>
   <!-- spring-cloud-starter-bootstrap -->
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-bootstrap</artifactId>
   </dependency>
</dependencies>
  • bootstrap.yml

server:
  port: 9006

spring:
  application:
    name: gateway03

  profiles:
    active: dev

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yml
  • Nacos配置中心

spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/order-system/**
          filters:
            - StripPrefix=1

        - id: storage-service
          uri: lb://storage-service
          predicates:
            - Path=/storage-system/**
          filters:
            - StripPrefix=1

4. 创建全局过滤器,检查token是否为空

创建全局过滤器:默认应用到所有的Route

1、实现GlobalFilter

2、实现 Ordered 接口进行过滤器排序

@Component
public class TokenFilter implements GlobalFilter, Ordered {

   @Override
   public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      // 请求对象
      ServerHttpRequest request = exchange.getRequest();
      // 响应对象
      ServerHttpResponse response = exchange.getResponse();

      String token = request.getHeaders().getFirst("token");
      if (StringUtils.isEmpty(token)) {
         return noAuth(response, ResultEnum.TOKEN_IS_NULL);
      }

      return chain.filter(exchange);
   }

   private Mono<Void> noAuth(ServerHttpResponse response, ResultEnum resultEnum) {
      response.getHeaders().set(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
      ResultVO<Object> resultVO = ResultVO.failed(resultEnum);
      String resultJson = JSONUtil.toJsonStr(resultVO);

      // WebFlux
      DataBuffer dataBuffer = response.bufferFactory().wrap(resultJson.getBytes());
      return response.writeWith(Mono.just(dataBuffer));
   }

   @Override
   public int getOrder() {
      return -200;
   }
}

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值