当前位置: 首页 > article >正文

Nacos + OpenFeign +Gateway

文章目录

  • Nacos
    • 注册中心 + 负载均衡
      • 依赖注入
      • 整合配置
      • 调用配置
    • 配置中心
      • 分环境配置
      • 读取配置信息
    • 总结
  • OpenFeign
    • 日志 + OpenFeign 配置
    • 拦截器
  • Gateway
    • 基础配置
    • 自定义断言工厂和过滤器

Nacos

nacos下载地址

# 1. 进入bin目录下打开命令行
# 2. windows启动nacos
startup.cmd -m standalone
# 2. linux启动nacos
startup.sh -m standalone
# 3. 启动后访问网址
http://localhost:8848/nacos/

项目对应版本 依赖文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <packaging>pom</packaging>
    <groupId>com.hebut</groupId>
    <artifactId>cloud_demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-cloud.version>2023.0.3</spring-cloud.version>
        <spring-cloud-alibaba.version>2023.0.3.2</spring-cloud-alibaba.version>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

注册中心 + 负载均衡

依赖注入

<!-- 服务发现 -->
<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>

整合配置

  1. 编写配置文件 application.properties
# nacos地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 服务名称
spring.application.name=service-order
# 端口
server.port=8080
  1. 开启服务注册/发现功能
@EnableDiscoveryClient //服务发现核心注解
@SpringBootApplication
public class OrderMainApplication {

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

}

调用配置

  1. 获取配置信息
    @Autowired
    DiscoveryClient discoveryClient;
    
    // 获取所有服务名称
    for (String service : discoveryClient.getServices()) {
        System.out.println(service);
        // 获取服务实例
        for (ServiceInstance instance : discoveryClient.getInstances(service)) {
            // 打印服务实例信息 ip + port + uri
            System.out.println(instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
        }
    }
  1. 调用配置 + 负载均衡
@Autowired
LoadBalancerClient loadBalancerClient;

// 1. 获取商品服务所在的所有机器的 ip + port
ServiceInstance choose = loadBalancerClient.choose("service-product");
// 2. 调用商品服务
String url = "http://" + choose.getHost() + ":" + choose.getPort() + "/product/" + id;
log.info("远程调用地址: " + url);
  1. 另一种 调用配置 + 负载均衡
@Configuration
public class OrderServiceConfig {

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

}
@Autowired
RestTemplate restTemplate;

// 用 服务名字service-product 动态确定服务地址
String url = "http://service-product/product/" + id;
Product product = restTemplate.getForObject(url, Product.class);

配置中心

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

分环境配置

在这里插入图片描述
在这里插入图片描述

创建 application.yml文件 删除原来的.properties文件

server:
  port: 8080
spring:
  application:
    name: service-order
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      config:
        namespace: dev
  config:
    import:
      - nacos:common.properties?group=order
      - nacos:database.properties?group=order

读取配置信息

在这里插入图片描述
在这里插入图片描述

把所有 import的配置文件中 以 order开头的配置都获取到

@Component
@ConfigurationProperties(prefix = "order") // 外部config配置优先
@Data
public class OrderProperties {
    private String timeout;
    // 驼峰映射
    private String autoConfirm;
    private String url;
}
// 方法一  不推荐!!!
@RefreshScope // 动态刷新nacos配置文件
@RestController
public class OrderController {

    // 获取nacos的配置文件内容
    @Value("${order.timeout}")
    String orderTimeout;
    @Value("${order.auto-confirm}")
    String orderAutoConfirm;
    @Value("${order.url}")
    String orderUrl;
// 方法二  推荐!!!
    @Autowired
    OrderProperties orderProperties;

    @GetMapping("/config")
    public String config() {
        return orderProperties.getTimeout() + " ; " + orderProperties.getAutoConfirm() + " ; " + orderProperties.getUrl();
    }

监听配置内容

@EnableDiscoveryClient  // 开启服务注册与发现
@SpringBootApplication
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    @Bean
    ApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager) {
        return args -> {
            nacosConfigManager.getConfigService().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);
                }
            });
        };
    }
}

总结

在这里插入图片描述

OpenFeign

openfeign官方文档

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

兜底回调 只有引入和配置了 sentinel 才能生效 否则会报错

@Component
public class ProductFeignFallback implements ProductFeignClient {
    @Override
    public Product getProductById(Long id) {
        System.out.println("兜底回调");
        Product product = new Product();
        product.setId(id);
        product.setPrice(new BigDecimal("0"));
        product.setNum(0);
        product.setProductName("测试商品");
        return product;
    }
}

发送请求接口

@FeignClient(value = "service-product",fallback = ProductFeignFallback.class)
public interface ProductFeignClient {

    // 发送请求
    @GetMapping("/product/{id}")
    Product getProductById(@PathVariable("id") Long id);
}

调用接口

    @Autowired
    ProductFeignClient productFeignClient;

	Product product = productFeignClient.getProductById(productId);

需要在启动类上面加上注解 !!!

@EnableFeignClients // 开启feign远程调用客户端

日志 + OpenFeign 配置

在这里插入图片描述

application.yml 配置文件编写

server:
  port: 8080
spring:
  application:
    name: service-order
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      config:
        namespace: dev
  config:
    import:
      - nacos:common.properties?group=order
      - nacos:database.properties?group=order
  profiles:
    # 调用resources下的其他配置文件
    include: feign
logging:
  level:
    com.hebut.order.feign: debug

feign 配置文件编写

spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            connectTimeout: 2000
            readTimeout: 5000
#            retryer: feign.Retryer.Default

@Configuration
public class OrderServiceConfig {

    // feign的debug日志
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
	
	// 连接超时或读取超时后重新发送请求的策略
	@Bean
    Retryer retryer() {
        // 不传参数就是默认
        return new Retryer.Default(100, SECONDS.toMillis(1), 5);
    }
}

拦截器

以请求拦截器为例

@Component
public class TokenRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        System.out.println("TokenRequestInterceptor");
        // 设置请求头的token
        requestTemplate.header("token", "admin");
    }
}

利用 HttpServletRequest request 获取请求头的内容

    @GetMapping("/product/{id}")
    public Product getProductById(@PathVariable("id") Long id,
                                  HttpServletRequest request) {
        Product product = productService.getProductById(id);
        System.out.println(request.getHeader("token"));
        return product;
    }

Gateway

基础配置

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</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-gateway</artifactId>
        </dependency>
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

在这里插入图片描述

server:
  port: 80
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  profiles:
    include: gateway
spring:
  cloud:
    gateway:
    # 跨域cors
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
      # 路由
      routes:
        # id 需要唯一
        - id: order-route
          # 需要访问的url
          uri: lb://service-order
          # 满足断言则访问上面的url
          predicates:
            - Path=/api/order/**
          # 访问url前的过滤器
          filters:
            - name: StripPrefix
              args:
                parts: 2
            - Token=token,jwt

        - id: product-route
          uri: lb://service-product
          predicates:
            - Path=/api/product/**
        - id: bing-route
          uri: https://cn.bing.com/
          predicates:
            - name: Path
              args:
                patterns: /search
            - name: Query
              args:
                param: q
                regexp: hello
            #            - Vip=user,zuo
            - name: Vip
              args:
                param: user
                value: zuo
      # 全局过滤器
      default-filters:
        - AddResponseHeader=X-Request-Foo, Zuo

自定义断言工厂和过滤器

gateway官方文档

断言工厂

@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {

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

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate(){
            @Override
            public boolean test(ServerWebExchange exchange) {
                String vip = exchange.getRequest().getQueryParams().getFirst(config.getParam());
                return vip != null && vip.equals(config.getValue());
            }
        };
    }

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

    public static class Config {
        private String param;
        private String value;
        public String getParam() {
            return param;
        }
        public void setParam(String param) {
            this.param = param;
        }
        public String getValue() {
            return value;
        }
        public void setValue(String value) {
            this.value = value;
        }
    }

}

过滤器

@Component
public class TokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    // TODO: 添加token校验逻辑
                    ServerHttpResponse response = exchange.getResponse();
                    HttpHeaders headers = response.getHeaders();
                    String value = config.getValue();
                    if ("uuid".equalsIgnoreCase(value)) {
                        value = UUID.randomUUID().toString();
                    }
                    if ("jwt".equalsIgnoreCase(value)) {
                        value = "jwt.Token";
                    }
                    headers.add(config.getName(), value);
                }));
            }
        };
    }
}

全局过滤器

@Component
@Slf4j
public class GlobalFilter implements org.springframework.cloud.gateway.filter.GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String url = request.getURI().getPath();
        long start = System.currentTimeMillis();
        log.info("请求路径:{}, 开始时间:{}",url,start);
        // 前置处理
        //拦截器
        Mono<Void> filter = chain.filter(exchange).doFinally(s -> {
            long end = System.currentTimeMillis();
            // .doFinally 是后置处理
            log.info("请求结束:{}, 结束时间:{}, 耗时:{}",url,end,end-start);
        });
        return filter;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

http://www.kler.cn/a/537997.html

相关文章:

  • python--sqlite
  • Centos挂载镜像制作本地yum源,并补装图形界面
  • Oracle迁移到MySQL
  • 字符串高频算法:无重复字符的最长子串
  • CSS Overflow 属性详解:控制内容溢出的利器
  • 公司配置内网穿透方法笔记
  • NO.9十六届蓝桥杯备战|4道习题|cin和cout(C++)
  • YOLOv11-ultralytics-8.3.67部分代码阅读笔记-tal.py
  • 百科词条创建审核不通过的原因有哪些?
  • RISCV基础知识
  • Matlab机械手碰撞检测应用
  • kubeadm构建k8s源码阅读环境
  • JAVA—SpringBoot—Vue篮球联赛校园管理系统
  • 激活函数篇 02 —— 双曲正切函数tanh
  • Eclipse IDE 快捷键大全
  • 镭速大文件传输软件如何邀请他人上传文件
  • 树和二叉树_6
  • Java序列化与反序列化:原理、实践与陷阱
  • Swift语言的云计算
  • 混合专家模型(MoE)概述:智能计算的新范式
  • Redis --- 使用HyperLogLog实现UV(访客量)
  • B树详解及其C语言实现
  • java 读取sq3所有表数据到objectNode
  • 使用TensorFlow和Keras构建卷积神经网络:图像分类实战指南
  • Maven插件—代码规范格式化spotless-maven-plugin
  • 记录虚拟机安装银河麒麟V10系统中遇到的一些问题