nacos和openfeign

为什么不用集群架构,而用分布式:

  1. 集群架构项目改了之后需要重新打包,重新部署,牵一发而动全身
  2. 有些服务可能不适合用java语言写,比如流媒体服务器,直播功能,甚至对视频做一些处理,,java语言可能不擅长这个,,一般用c++开发,,就必须用分布式

分布式架构需要消除单点故障

Nacos

注册中心

每一个服务上线或者下线的是否,都去告诉nacos,nacos作为注册中心,维护了,这些服务节点的信息

nacos官网: https://nacos.io/docs/v2.4/quickstart/quick-start/

下载对应版本nacos,以单机模式启动

shell 复制代码
# -m : mode 什么模式
startup.cmd -m standalone

http://localhost:8848/nacos

cloud版本:

springboot使用nacos:

导入依赖:

xml 复制代码
<!--        服务发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

@EnableDiscoveryClient开启服务发现的功能

spring容器会有一个DiscoveryClient的Bean,,

  • getServices() : 获取所有的服务
  • getInstances("服务名字") : 获取指定服务名字的实例,,可能是多个实例
    • 返回的ServiceInstance实例,可以从中获取到ip和port,,进行远程调用

上面是获取指定某一个实例去调用,,实际中不可能请求都打在一个实例上,,需要将请求负载均衡:

引入spring-cloud-starter-loadbalancer

xml 复制代码
     <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

引入这个包之后,spring容器中会有一个负载均衡的客户端LoadBalancerClient,可以通过LoadBalancerClientchoose(服务名字)通过负载均衡,选择一个实例返回:

java 复制代码
    @Autowired
    private LoadBalancerClient loadBalancerClient;

  // 负载均衡调用 product
    public Product getProductFromRemoteWithLoadBalance(Long productId){
        ServiceInstance choose = loadBalancerClient.choose("service-product");

        String url = "http://"+choose.getHost()+":"+choose.getPort()+"/product/"+productId;

        // 给远程发送请求
        log.info("远程请求:{}",url);

        Product product = restTemplate.getForObject(url, Product.class);
        return product;
    }

但是一般不会这样用,,,

也可以使用@LoadBalanced 打在RestTemplate的bean上面,这样,直接通过restTemplate就可以直接负载均衡发送请求:

java 复制代码
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    
    
      /**
     * 基于注解的 负载均衡   @LoadBalancer,,, url的host换成服务名字
     * @return
     */
    private Product getProductFromRemoteWithLoadBalancerAndAnnotation(Long productId){
        String url = "http://service-product/product/"+productId;

        // 底层去负载均衡的,,这里看不到他具体调用了哪个的日志
        Product product = restTemplate.getForObject(url, Product.class);
        return product;
    }

但是一般也不会这样用,,都是直接集成openfeign,openfeign直接发送网络请求,自带负载均衡,还有一些重试,兜底,拦截器等功能

nacos作为配置中心

依赖:

xml 复制代码
<!--        nacos作为配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

nacos中的配置中心,使用了spring.config.import ...这个是springboot2.4之后的特性,,自动导入配置文件,,配置文件生效的规则就是:

  1. 先导入的先生效,,后导入的如果有属性和先导入的重复了,,使用先导入的

一旦统一引入了nacos配置的依赖,,如果当前服务没有指定对应的配置,,项目启动就会报错,,可以暂时使用spring.cloud-nacos.config.import-check.enabled=false关闭配置中心

nacos配置文件分环境,服务,数据集(每个具体的配置文件)

  • 名称空间 :区分多套环境 dev ,prod
    • group : 区分是哪一种微服务,,比如是order 还是 product
      • 数据集 : 配置文件,比如common.properties,database.properties

配置文件中设置名称空间 spring.cloud.nacos.config.namespace=dev

在导入的使用,,使用 group=xxx 区分是哪一个组,,

在nacos中创建名称空间和配置文件:

yml 复制代码
spring:
  application:
    name: service-order
  cloud:
    nacos:
      # 配置注册中心的位置,,, 项目启动就会去注册
      server-addr: 127.0.0.1:8848
      config:
        # 读取的是 这个名称空间的 配置
        namespace: dev
  config:
    # 自动导入这个配置文件  ===》 灵活,统一的导入外部配置源,,, 替代了旧版本中部分零散的配置方式
    # 显示指定要导入当前应用中的额外配置源
    import:
      # 导入 order组的配置
      - nacos:common.properties?group=order
      - nacos:datasource.properties?group=order

server:
  port: 8000


order:
  timeout: 111
  auto-confirm: 222

配置文件实时更新:

使用@ConfigurationProperties,nacos配置文件改了之后,会实时更新
@Value引入不会实时更新,,但是在类上加上@RefreshScope

NacosConfigManager: 会将nacos拉取的配置融入spring的Environment体系,
NacosConfigManager能获取到ConfigService: 这个是nacos官方提供的底层客户端接口,,负责与Nacos服务建立连接,拉取配置,监听配置变更,,,

监听配置文件变更发送通知:

java 复制代码
    /**
     * 项目启动之后执行,,, 在CommandLineRunner后面
     * @param nacosConfigManager :  nacos配置中心交互的 核心管理类 ---》 封装了底层的配置连接,拉取,监听等核心逻辑,,让你无需手动处理Nacos客户端的创建和管理
     *                           spring应用与 Nacos配置中心之间的 桥梁,统一管理Nacos配置客户端(configService),配置拉取,配置监听等操作
     *
     *                           ConfigService : nacos官方提供的底层客户端接口,,, 负责与Nacos服务建立连接,拉取配置,监听配置变更,,,
     *                           NacosConfigManager 可以获取到ConfigService 实例
     *
     *
     *                           NacosConfigManager 会将从Nacos拉取的配置融入 Spring的Environment体系,,比如@Value,@ConfigurationProperties能读取nacos配置
     * @return
     */
    @Bean
    ApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager){
        return new ApplicationRunner() {
            @Override
            public void run(ApplicationArguments args) throws Exception {
                System.out.println("==============");

                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 configInfo) {
                        // 接收配置信息
                        System.out.println("configInfo = " + configInfo);

                        System.out.println("邮件通知。。。");
                    }
                });

            }
        };
    }

yml中--- 文档分隔符,, 在同一个yml文件中,分隔成多个独立的,完整的yaml文档,,每一个---分隔的部分都是一个独立的yaml结构

解决了,单个文件存储多套配置的问题,,可以将,开发,测试,生产的配置文件都写在一个yml中

nacos在不同的 名称空间 引入不同个数的配置文件,,可以使用---文档分隔符

yml 复制代码
spring:
  application:
    name: service-order
  cloud:
    nacos:
      # 配置注册中心的位置,,, 项目启动就会去注册
      server-addr: 127.0.0.1:8848
      config:
        # 读取的是 这个名称空间的 配置 ===> 动态取值 ===> 如果没有配置,,默认是public
        namespace: ${spring.profiles.active:public}
  profiles:
    active: dev
    include: feign  # 除了dev,,还包含了feign环境

server:
  port: 8000


order:
  timeout: 111
  auto-confirm: 222


# 开启openfeign日志
logging:
  level:
    com.cj.order.feign: debug

---
# 生产环境 和 开发环境,, 导入的配置文件个数也不一致 ,,  --- : 文档分隔符,,每个被分割的部分都是一个独立的yaml,,默认不激活,,满足条件才会激活
spring:
  config:
    import:
        - nacos:common.properties?group=order
        - nacos:datasource.properties?group=order
    activate:
      on-profile: dev

---

spring:
  config:
    import:
      - nacos:common.properties?group=order
      - nacos:datasource.properties?group=order
      - nacos:xxx.properties?group=order
    activate:
      on-profile: prod

OpenFeign使用

openfeign是spring cloud中 声明式的http客户端,,用注解和接口来简化微服务之间的远程调用,,

可以重试,兜底,拦截器

开启openfeign远程调用:@EnableFeignClients,用@FeignClient标注发请求的客户端

记录openfeign远程调用日志

在yml中,设置日志级别

yml 复制代码
# 开启openfeign日志
logging:
  level:
    com.cj.order.feign: debug

注入日志的bean

java 复制代码
  // feign打印日志
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
设置超时自动中断

服务之间调用,长时间没有相应,,会导致请求积压,服务雪崩,,需要引入超时机制

超时分为 : 连接超时读取超时

yml 复制代码
spring:
  cloud:
    openfeign:
      client:
        config:
          # 默认设置
          default:
            logger-level: full
            connect-timeout: 2000
            read-timeout: 3000
          # 对这个service-product客户端的配置
          service-product:
            logger-level: full
            connect-timeout: 3000
            read-timeout: 5000
            # 这样配置只针对这个服务有效
#            request-interceptors:
#              - com.cj.order.interceptor.XTokenRequestInterceptor
feign:
  sentinel:
    # 开启之后,远程调用失败,,就会自动走,,兜底的方法
    enabled: true
重试

openfeign默认不重试,,当时可以配置重试

java 复制代码
    /**
     * openfeign 的重试 器,,, 间隔100ms重试一次,最大1s,,重试次数为3,,,, 下一次就会是100*1.5 ,,, 直到1s
     * @return
     */
    @Bean
    Retryer retryer(){
       return new Retryer.Default(100, 1, 3);
   }
拦截器

分为请求拦截器响应拦截器 ,,, 可以在配置文件中,单独给某个服务配置拦截器,,,也可以将拦截器注入到spring容器,,所有的openfeign请求都会被拦截

java 复制代码
/**
 * 想要让拦截器生效,,第一种方法,,在配置文件中指定拦截器
 */
@Component // 容器中只要有这个RequestInterceptor,,,他就会自动调用上,,每一次请求都会应用这个拦截器
public class XTokenRequestInterceptor implements RequestInterceptor {

    /**
     *
     * @param requestTemplate  这次请求的详细信息,,,如果需要对这次请求进行修改,,直接修改这个RequestTemplate
     */
    @Override
    public void apply(RequestTemplate requestTemplate) {

        System.out.println("xTokenInterceptor,,,,");
        // 给请求添加请求头,或者是请求体
        requestTemplate.header("X-Token", UUID.randomUUID().toString());
//        requestTemplate.header()

    }
}

可以用来整个链路共享数据

兜底fallback

需要配合sentinel才能使用默认的兜底策略

引入sentinel:

xml 复制代码
 <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
java 复制代码
/**
 * 兜里回调
 */
@Component
public class ProductFeignClientFallback implements ProductFeignClient {
    @Override
    public Product getProductById(Long id) {

        System.out.println("兜底回调");
        // 远程失败了,,才会走这里
        Product product = new Product();
        product.setProductName("未知商品");

        return product;
    }
}

在openfeign的调用里面,声明fallback:

java 复制代码
// contextId是客户端的名字,,, 如果不写的话,,客户端名字默认是value值
//@FeignClient(value = "service-product",contextId = "product-feignclient")
@FeignClient(value = "service-product",fallback = ProductFeignClientFallback.class)
public interface ProductFeignClient {

    //
    @GetMapping("/product/{id}")
    Product getProductById(@PathVariable("id") Long id);

}
openFeign调用外部接口

openfeign不仅能发送服务之间的调用,也能直接对外部的api发送请求

java 复制代码
// 也可以之前放请求
@FeignClient(value = "weather-client",url = "http://www.baidu.com")
public interface WeatherFeignClient {

    @PostMapping("/xxx")
    String getWeather(@RequestHeader("Authorization") String auth, @RequestParam("token") String token,@RequestParam("cityId") String cityId);
相关推荐
Dragon Wu5 天前
SpringCache 缓存使用总结
spring boot·后端·spring·缓存·springcloud
七夜zippoe5 天前
微服务链路追踪实战:SkyWalking vs Zipkin 架构深度解析与性能优化指南
java·开发语言·微服务·springcloud·sleuth·zipkin
梦想总是可以实现的8 天前
SpringCloud2024 + JDK17实战:手把手教你从零搭建微服务全家桶(含Eureka+Gateway+Redis)
springcloud·微服务架构·java开发·分布式系统
九转苍翎15 天前
微服务学习笔记(1)——SpringColud概述
spring boot·maven·springcloud
七夜zippoe16 天前
OpenFeign全解 声明式REST客户端原理与配置实战
java·负载均衡·springcloud·openfeign·动态代理·核心配置
CodeCaptain21 天前
nacos-2.3.2-OEM与nacos3.1.x的差异分析
java·经验分享·nacos·springcloud
Dragon Wu21 天前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
七夜zippoe23 天前
分布式配置中心终极对决 Spring Cloud Config与Apollo架构深度解析
分布式·架构·springcloud·apollo·配置中心
没有bug.的程序员25 天前
Spring Cloud Alibaba:Nacos 配置中心与服务发现的工业级深度实战
java·spring boot·nacos·服务发现·springcloud·配置中心·alibaba
短剑重铸之日1 个月前
《SpringCloud实用版》Stream + RocketMQ 实现可靠消息 & 事务消息
后端·rocketmq·springcloud·消息中间件·事务消息