目录

Nacos版本对应  

Nacos Windows版安装路径

Nacos快速入门         

 Nacos服务注册与服务发现

 Nacos服务注册

Nacos服务发现

Nacos配置

 Nacos集群

Nacos配置文件

配置文件刷新

配置空间读取规则

命名空间以及Group

命名空间

多配置文件时

Ribbon

Openfeign

 简介

应用场景 

操作过程

手写Feign

Feign的参数调用(重点掌握)

Hystrix

简介        

使用场景

使用方法

拦截器状态

常见配置


Nacos版本对应  

      首先我们要知道Nacos版本与Spring-Cloud-Alibaba对应的版本以及Spring-Clound对应的版本,如果版本对应的不一致的话,有时候会导致不必要的麻烦

 Nacos Windows版安装路径

        这里我们采用的2.0.3的版本,下载后解压缩后三步走就可以使用。

        1.打开nacos-》conf-》nacos-mysql.sql文件将这个文件导入我们的数据库里面。

        

        2. 打开nacos-》conf-》application.properties进入将33 36 39 40 41 44 45 46 47行解开应用,在39 40 41行

db.url.0=jdbc:mysql://本地数据库的名字:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
 db.user.0=数据库账号
 db.password.0=数据库密码

        3. 打开nacos-》bin-》startup.cmd右键打开查看里面的配置

        这个是打开的方式,我们将他修改为单机模式,就可以双击运行了

                standalone:单机模式

                cluster:集群模式

        运行成功界面 

         在浏览器输入localhost:8848/nacos进入nacos界面,账号密码都是:nacos

Nacos快速入门         

        创建idea的Spring Initializr选择

         

        创建成功后进入pom文件修改版本,将画住的地方修改。    

         修改配置文件,我使用的.yml样式

server:
  port: 8081
spring:
  application:
    name: nacos-client-a
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos

        在启动类上面加入一个注解@EnableDiscoveryClient 就可以启动了

server:
  port: 8081        端口号
spring:
  application:
    name: nacos-client-a        服务注册的名字
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848        nacos的地址
        username: nacos        nacos账号
        password: nacos        nacos密码

  Nacos服务注册与服务发现

  Nacos服务注册

        完成上面的启动,我们重新创建一个一摸一样,我们添加一个controller

@RestController
public class AController {
//打招呼的接口
    @GetMapping("hello")
    public String hello(String name) {
        return "hello" + name;
    }
}

        运行就完成了服务注册,我们可以在网址上查看一下时候运行成功。

        网址 localhost:端口号/hello?name

Nacos服务发现

        重复上面的步骤到添加一个controller,这里要注意的是配置文件里面的端口号要修改,不然会存在端口号被占用。

@RestController
public class BController {
//    注册服务发现组件
    @Autowired
    private DiscoveryClient discoveryClient;
             //服务发现接口
    @GetMapping("discovery")
    public String dicoveryService(String serviceId){
        //根据实例名称拿到实例集合
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        //根据实例集合拿到一个实例对象
        ServiceInstance serviceInstance = instances.get(0);
        System.out.println(serviceInstance.getHost()+":"+serviceInstance.getPort());
       return serviceInstance.getHost()+":"+serviceInstance.getPort();
    }
}

        运行就可以完成服务发现,我们可以在网址上查看一下时候运行成功。

        网址 localhost:端口号/discovery?serviceId=服务注册的名字

Nacos配置

 Nacos集群

       nacos-》conf-》application.properties ,创建三个nacos修改21行分别是8848,8849,8850

    nacos-》conf-》新建一个文件cluster.conf,记事本打开加入

端口号:8848

端口号:8849

端口号:8850

        nacos-》bin-》startup.cmd修改为集群模式

        连着启动三个,就会打开集群模式

Nacos配置文件       

        创建完成后第一步就是去修改对应的版本,加入一个lombok依赖

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.24</version>
            </dependency>

        我们打开配置会发现多了一个配置

        

        bootstrap是提前加载,可以看出图标有一个云是加载云上的配置,也就是加载nacos的配置

server:
  port: 8888
spring:
  application:
    name: nacos-config
    #项目启动时去哪里找他的配置文件
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        username: root
        password: root
        #这里开始就是开始寻找他的配置文件
        prefix: nacos-config       #读那个配置文件
        file-extension: yml     #文件类型,不写默认properties
#        namespace: #不写默认public
#       group:  #不写默认DEFAULT_GROUP

        在Nacos里面建立一个配置文件 

        建立一个controller

@RestController
public class NacosConfigConfiguration {
    @Value("${hero.name}")
    private String name;
    @Value("${hero.age}")
    private Integer age;
    @Value("${hero.address}")
    private  String address;

    @GetMapping("info")
    public String info(){
        return name+":"+age+":"+address;
    }
}

        运行,只要是不报错就是调用成功,进入网址确认

        网址 localhost:端口号/info

        

配置文件刷新

        当我们修改Nacos里面的配置文件,对应调用配置文件的项目如何进行同步更新。

                如果是项目下线重新运行的话,一个两个还可以,如果是成百上千个工作量就大的离谱。这时候我们就需要一种修改配置文件的时候,项目里面的文件也能同步更新的方法。

        优化上面的代码

        新建一个实体类Hero

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@RefreshScope  //给这个类 添加一个刷新的作用域
public class Hero {
    @Value("${hero.name}")
    private String name;
    @Value("${hero.age}")
    private Integer age;
    @Value("${hero.address}")
    private  String address;

}

        @RefreshScope         加入这个注解就可以实时进行刷新

        对应的controller也要进行优化

@RestController
public class NacosConfigConfiguration {
    @Autowired
    private Hero hero;

    @GetMapping("info")
    public String info() {

        return hero.getName() + ":" + hero.getAge() + ":" + hero.getAddress();
    }
}

配置空间读取规则

         

nacos 配置中心通过 namespace dataId group 来唯一确定一条配置。
Namespace :即命名空间。默认的命名空间为 public ,我们可以在 Nacos 控制台中新建
命名空间;
dataId :即配置文件名称
Group : 即 配 置 分 组 , 默 认 为 DEFAULT_GROUP , 可 以 通 过
spring.cloud.nacos.config.group 配置。
其中: dataId 是最关键的配置字段:格式如下:
${prefix} - ${spring.profiles.active} . ${file-extension}
说明:
prefix 默 认 为 spring.application.name 的 值 , 也 可 以 通 过 配 置 项
spring.cloud.nacos.config.prefix 来配置;
spring.profiles.active 即 为 当 前 环 境 对 应 的 profile 。 注 意 , 当
spring.profiles.active 为空时,对应的连接符 - 也将不存在, dataId 的拼接格式变
${prefix}.${file-extension}
file-extension 为 配 置 内 容 的 数 据 格 式 , 可 以 通 过 配 置 项
spring.cloud.nacos.config.file-extension 来配置。

命名空间以及Group

        Nacos的隔离级别有两种一种是命名空间一种是Group

命名空间

        新建命名空间

命名空间ID如果不写就会自动生成一个uuid

命名空间别名就是起一个名字

描述 就是描述命名空间

 多配置文件时

        Nacos创建新的配置,这里的配置的后缀得加上时什么文件,不然会扫描不上

        在配置类加入

 profiles:
    active:后缀名

server:
  port: 8082
spring:
  application:
    name: nacos-client-b
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        prefix: nacos-config
        file-extension: yml
  profiles:
    active: dev

Ribbon

Openfeign

 简介

        Feign 是 声明性 ( 注解 ) Web 服务 客户端 。它使编写 Web 服务客户端更加容易。 要使用 Feign 请创建一个接口并对其进行注解 。它具有可插入注解支持,包括 Feign 注解和 JAX-RS 注解。 Feign 还支持可插拔编码器和解码器。 Spring Cloud 添加了对 Spring MVC 注解的支持 ,并
支持使用 HttpMessageConverters Spring Web 中默认使用的注解。 Spring Cloud 集成了Ribbon 和 Eureka 以及 Spring Cloud LoadBalancer ,以 在使用 Feign 时提供负载平衡 http 客户端

应用场景 

      比如订单系统,用户要下订单,但是订单的相关代码在user-service里面没有,在order-service里面有,这时候我们就要使用user-service去调用order-service里面接口来完成用户下单的操作。        

操作过程

 建立一个user

        按照上面的操作修改pom文件里面的版本

        建立起yml配置文件

server:
  port: 9001
spring:
  application:
    name: nacos-openfeign-user
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos

        建立controller

@RestController
public class UserController {

    @GetMapping("user")
    public String user(){
        return "这是user类";
    }

}

        启动类加入Nacos的启动注解

@SpringBootApplication
@EnableDiscoveryClient
public class NacosOpenfeignUserApplication {

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

 建立一个order,选中openfeign

         修改pom的文件的版本

        加入yml配置信息

server:
  port: 9002
spring:
  application:
    name: nacos-openfeign-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos

        根据openfeign的简介我们可以看出,openfeign建立主要分为三步

        1.声明性(注解)web服务客户端

                   加入启动类注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class NacosOpenfeignServiceApplication {

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

}

@EnableFeignClients:开启feign的客户端功能 才可以帮助我们发起调用

         2.要使用Feign,创立一个接口并对其进行注解

                建立一个feign包,里面创建feign类   注:起名规范:比如是user调用order类的起名为UserOrderFeign

               建立feign类

@FeignClient(value = "nacos-openfeign-user")
public interface UserOrderOpenfeign {

    @GetMapping("user")
    public String user();
}

@FeignClient(value = "nacos-openfeign-user") :这是feign注解

        nacos-openfeign-user:这是提供者提供的nacos的服务名

                提供者:就是被调用的一方;

@GetMapping("user")

public String user();

        这是一个完整的方法签名

                        方法签名就是一个方法的全部——修饰符 返回值 方法名以及方法的注解

        3.建立controller进行调用

    

@RestController
public class ServiceController {
    @Autowired
   private UserOrderOpenfeign userOrderOpenfeign;

    @GetMapping("service")
    public String service() {
        String user = userOrderOpenfeign.user();
        return user;

    }

}

        两个都得运行,首先得运行user,然后运行service,进入网址确认

        网址:localhost:9002/service 

     如果提供者延时了两秒就会报错,因为feign的默认等待时间是1S;我们可以使用睡眠让user睡眠两秒,在用网址测的时候就会发现报500错误,在控制台上显示连接超时;

        解决方法是加入配置信息,由于feign只是帮你封装了远程调用的功能,底层还是ribbon,所以超时的配置还是ribbon的配置

ribbon:
  ReadTimeout: 3000
  ConnectTimeout: 3000

ReadTimeout: 3000 :3S超时时间

ConnectTimeout: 3000 :链接服务的超时时间

手写Feign


@SpringBootTest
class ApplicationTests {
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 手写feign的核心步骤
     */
    @Test
    void contextLoads() {
        UserOrderFeign o = (UserOrderFeign) Proxy.newProxyInstance(UserController.class.getClassLoader(), new Class[]{UserOrderFeign.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 能去拿到对方的ip和port 并且拿到这个方法上面的注解里面的值 那么就完事了
                GetMapping annotation = method.getAnnotation(GetMapping.class);
                String[] paths = annotation.value();
                String path = paths[0];
                Class<?> aClass = method.getDeclaringClass();
                FeignClient annotation1 = aClass.getAnnotation(FeignClient.class);
                String applicationName = annotation1.value();
                String url = "http://" + applicationName + "/" + path;
                String forObject = restTemplate.getForObject(url, String.class);
                return forObject;
            }
        });
        String s = o.doOrder();
        System.out.println(s);
    }

}

Feign的参数调用(重点掌握)

        提供端建立实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Order {

    private Integer id;
    private String name;
    private Double price;
    private Date time;

}

        提供端controller


/**
 * url    /doOrder/热干面/add/油条/aaa
 * get传递一个参数
 * get传递多个参数
 * post传递一个对象
 * post传递一个对象+一个基本参数
 */
@RestController
public class ParamController {

    @GetMapping("testUrl/{name}/and/{age}")
    public String testUrl(@PathVariable("name") String name, @PathVariable("age") Integer age) {
        System.out.println(name + ":" + age);
        return "ok";
    }

    @GetMapping("oneParam")
    public String oneParam(@RequestParam(required = false) String name) {
        System.out.println(name);
        return "ok";
    }


    @GetMapping("twoParam")
    public String twoParam(@RequestParam(required = false) String name, @RequestParam(required = false) Integer age) {
        System.out.println(name);
        System.out.println(age);
        return "ok";
    }

    @PostMapping("oneObj")
    public String oneObj(@RequestBody Order order) {
        System.out.println(order);
        return "ok";
    }


    @PostMapping("oneObjOneParam")
    public String oneObjOneParam(@RequestBody Order order,@RequestParam("name") String name) {
        System.out.println(name);
        System.out.println(order);
        return "ok";
    }


    ////////////////// 单独传递时间对象

    @GetMapping("testTime")
    public String testTime(@RequestParam Date date){
        System.out.println(date);
        return "ok";
    }
}

        接收端feign类里面的接口


/**
 * @FeignClient(value = "order-service")
 * value 就是提供者的应用名称
 */
@FeignClient(value = "order-service")
public interface UserOrderFeign {

    /**
     * 你需要调用哪个controller  就写它的方法签名
     * 方法签名(就是包含一个方法的所有的属性)
     *
     * @return
     */
    @GetMapping("doOrder")
    String doOrder();

    @GetMapping("testUrl/{name}/and/{age}")
    public String testUrl(@PathVariable("name") String name, @PathVariable("age") Integer age);

    @GetMapping("oneParam")
    public String oneParam(@RequestParam(required = false) String name);

    @GetMapping("twoParam")
    public String twoParam(@RequestParam(required = false) String name, @RequestParam(required = false) Integer age);

    @PostMapping("oneObj")
    public String oneObj(@RequestBody Order order);


    @PostMapping("oneObjOneParam")
    public String oneObjOneParam(@RequestBody Order order, @RequestParam("name") String name);



    @GetMapping("testTime")
    public String testTime(@RequestParam Date date);
}

        接收端的实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Order {

    private Integer id;
    private String name;
    private Double price;
    private Date time;

}

        接收端controller


@RestController
public class UserController {

    /**
     * 接口是不能做事情的
     * 如果想做事 必须要有对象
     * 那么这个接口肯定是被创建出代理对象的
     * 动态代理 jdk(java interface 接口 $Proxy )  cglib(subClass 子类)
     * jdk动态代理 只要是代理对象调用的方法必须走 java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
     */
    @Autowired
    public UserOrderFeign userOrderFeign;

    /**
     * 总结
     * 浏览器(前端)-------> user-service(/userDoOrder)-----RPC(feign)--->order-service(/doOrder)
     * feign的默认等待时间时1s
     * 超过1s就在直接报错超时
     *
     * @return
     */
    @GetMapping("userDoOrder")
    public String userDoOrder() {
        System.out.println("有用户进来了");
        // 这里需要发起远程调用
        String s = userOrderFeign.doOrder();
        return s;
    }



    @GetMapping("testParam")
    public String testParam(){
        String cxs = userOrderFeign.testUrl("cxs", 18);
        System.out.println(cxs);

        String t = userOrderFeign.oneParam("老唐");
        System.out.println(t);

        String lg = userOrderFeign.twoParam("雷哥", 31);
        System.out.println(lg);

        Order order = Order.builder()
                .name("牛排")
                .price(188D)
                .time(new Date())
                .id(1)
                .build();

        String s = userOrderFeign.oneObj(order);
        System.out.println(s);

        String param = userOrderFeign.oneObjOneParam(order, "稽哥");
        System.out.println(param);
        return "ok";
    }

    /**
     * Sun Mar 20 10:24:13 CST 2022
     * Mon Mar 21 00:24:13 CST 2022  +- 14个小时
     * 1.不建议单独传递时间参数
     * 2.转成字符串   2022-03-20 10:25:55:213 因为字符串不会改变
     * 3.jdk LocalDate 年月日    LocalDateTime 会丢失s
     * 4.改feign的源码
     *
     * @return
     */
    @GetMapping("time")
    public String time(){
        Date date = new Date();
        System.out.println(date);
        String s = userOrderFeign.testTime(date);

        LocalDate now = LocalDate.now();
        LocalDateTime now1 = LocalDateTime.now();

        return s;
    }



}

Hystrix

简介        

        熔断器,也叫断路器!(正常情况下 断路器是关的 只有出了问题才打开)用来保护微服务不 雪崩的方法
        Hystrix 是 Netflix 公司开源的一个项目,它提供了熔断器功能,能够阻止分布式系统中出现 联动故障 。Hystrix 是通过隔离服务的访问点阻止联动故障的,并提供了故障的解决方案,从而提高了整个分布式系统的弹性。

使用场景

        服务A调用服务B,服务B调用服务C,服务C挂掉了,服务A和服务B一直在等待服务C。占据线程不放掉。就是用熔断器。

使用方法

       调用的一方加入依赖

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

        在feign包里面建立hystrix包,新建一个类继承feign接口

@Component
public class ConsumerProviderHystrix implements ConsumerProviderFeign {
    @Override
    public String provider() {
        return "null";
    }
}

        在feign接口的注解里面加入fallback指向熔断后的路径也就是刚才建立的hystrix包里新建的类

@FeignClient(value = "hystrix-provinder", fallback =ConsumerProviderHystrix.class)
public interface ConsumerProviderFeign {

    @GetMapping("provider")
    public String provider();

}

        启动类加入hystrix注解 @EnableHystrix

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class HystrixConsumerApplication {

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

}

        在配置中打开hystrix,默认是关闭的

server:
  port: 9022
spring:
  application:
    name: hystrix-consumer
  cloud:
    nacos:
      discovery:
        username: nacos
        password: nacos
        server-addr: localhost:8848
feign:
  hystrix:
    enabled: true

拦截器状态

         拦截器状态有三种

                关:默认情况下,断路器是关闭的,正常使用

                开:当在一个时间窗口内(10S)访问失败的次数到达一个阈值,断路器开

                半开:让少许流量去尝试调用,如果正常了,就关掉断路器

常见配置

hystrix:    #hystrix的全局控制
    command:
        default:    #default是全局控制,也可以换成单个方法控制,把default换成方法名即可
            circuitBreaker:
                enabled: true   #开启断路器
                requestVolumeThreshold: 3   #失败次数(阀值)  10次
                sleepWindowInMilliseconds: 20000    #窗口时间
                errorThresholdPercentage: 60    #失败率
            execution:
                isolation:
                    Strategy: thread  #隔离方式 thread线程隔离集合和semaphore信号量隔离级别
                    thread:
                        timeoutInMilliseconds: 3000 #调用超时时长
            fallback:
                isolation:
                    semaphore:
                        maxConcurrentRequests: 1000 #信号量隔离级别最大并发数
ribbon:
    ReadTimeout: 5000   #要结合feign的底层ribbon调用的时长
    ConnectTimeout: 5000
#隔离方式 两种隔离方式  thread线程池 按照group(10个线程)划分服务提供者,用户请求的线程和做远程的线程不一样
# 好处 当B服务调用失败了 或者请求B服务的量太大了 不会对C服务造成影响 用户访问比较大的情况下使用比较好  异步的方式
# 缺点 线程间切换开销大,对机器性能影响
# 应用场景 调用第三方服务 并发量大的情况下
# SEMAPHORE信号量隔离 每次请进来 有一个原子计数器 做请求次数的++  当请求完成以后 --
# 好处 对cpu开销小
# 缺点 并发请求不易太多 当请求过多 就会拒绝请求 做一个保护机制
# 场景 使用内部调用 ,并发小的情况下
# 源码入门  HystrixCommand  AbstractCommand HystrixThreadPool 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐