微服务——Nacos配置管理模型

1.如何在IDEA中启动Nacos?

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

2.Nacos配置中心宕机了,我们的服务还可以读取到配置信息吗?

可以从内存,客户端获取了配置中心的配置信息以后,会将配置信息在本地内存中存储一份
在本地中靠Map对象存储

2.1长轮询

客户端每隔30s向Nacos配置中心发起一次请求,拉取一次配置信息 wait29.5s
没有配置更新时,客户端会在Nacos服务端的队列中等待
每隔XX秒发送一次请求?定时任务调度

2.2如何在Java中实现定时任务调度?

2.2.1单线程执行定时任务调度

  • Timer对象(import java.util.Timer;)
    创建对象时,会创建一个线程,并且为线程分配一个任务队列,顺序执行
  • TimerTask 任务执行对象
package com.jt.common.util;

import java.util.Timer;
import java.util.TimerTask;

/*单线程定时任务工具类*/
public class TimerUtils {
    public static void main(String[] args) {
        //1.构建执行任务对象
        Timer timer=new Timer();/*创建对象时,会创建一个线程,并且为线程分配一个任务队列*/
        //2.构建任务对象
        TimerTask task1=new TimerTask() {
            @Override
            public void run() {
                System.out.println(System.currentTimeMillis());
            }
        };
        //3.定时执行任务
        timer.schedule(task1, 1000, 1000);
    }
}

实现效果
在这里插入图片描述
结束任务

timer.cancle();

在这里插入图片描述

  • 缺陷:不能并发执行,因为只有一个线程执行多次任务,谁先来谁先执行

2.2.2多线程执行定时任务

  • Timer ScheduledExecutorService 多线程的任务调度
    实现代码
package com.jt.common.util;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/*多线程定时任务工具类*/
public class ScheduledExecutorServiceUtils {

    public static void main(String[] args) {
        /*1.构建一个负责任务调度的线程池对象*/
        ScheduledExecutorService scheduledExecutorService =
                Executors.newScheduledThreadPool(5);
        /*2.任务对象*/
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                String tName=Thread.currentThread().getName();
                System.out.println(tName+"->"+System.currentTimeMillis());
            }
        };
        /*3.任务调度*/
        scheduledExecutorService.
                scheduleAtFixedRate(runnable,1000,//1s以后开始执行
                                                 1000,//每隔1s开始执行 与任务是否执行完毕无关
                                      TimeUnit.MILLISECONDS);//时间单位
    }
}

实现效果
在这里插入图片描述

3.Nacos的配置管理模型——命名空间

  • 配置管理模型作用:区分配置、管理配置,通过Namespace、group、Data ID能够定位到一个配置集

3.1新建命名空间

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

3.2克隆配置中心

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

3.3修改dev的配置信息

在这里插入图片描述

3.4配置后端yml文件

在这里插入图片描述

server:
  port: 8082
spring:
  application:
    name: sca-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #假如nacos和你的服务在一台电脑上,默认服务本机,是可以省略的
      config:
        server-addr: localhost:8848 #配置中心的地址
        file-extension: yml #添加配置中心配置格式
        namespace: 1ec9fffa-c171-458d-815d-502a52daf446 #指定命名空间
logging:
  level:
    com.jt: debug #配置com.jt包以及子包中的日志级别 默认是info

public配置信息
在这里插入图片描述
dev配置信息
在这里插入图片描述
测试结果
在这里插入图片描述
说明读取的是指定命名空间的配置中心信息,也就是dev中的sca-provider名字的配置信息
若不指定命名空间,则默认为pubilic空间

4.Nacos的配置管理模型——分组设计

4.1新建分组配置

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

4.2配置分组id

在这里插入图片描述

4.3新建Controller层

package com.jt.provider.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RefreshScope
@RestController
public class ProviderCacheController {
    @Value("${useLocalCache:false}")
    private boolean useLocalCache;

    @RequestMapping("/provider/cache")
    public String doUseLocalCache(){
        return "useLocalCache'value is   "+useLocalCache;
    }
}

实现效果
在这里插入图片描述

  • ArrayList线程不安全
  • Vector线程安全但性能差 悲观锁
  • CopyOnWriteArrayList(JDK1.5)保证集合的线程安全 乐观锁
  • mysql 使用的是悲观锁

4.4双重校验锁机制

package com.jt.common.thread;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class SyncTests {

    //private static List<String> cache=new Vector<>();
    //CopyOnWriteArrayList是一个线程安全的List集合,允许多个线程执行并发更新,但是只能有一个更新成功.
    private static List<String> cache=new CopyOnWriteArrayList<>();//CAS(比较和交换)

    //    public synchronized static List<String> selectAll(){
//        if (cache.isEmpty()) {
//              System.out.println("Get Data From Database");
//              List<String> data = Arrays.asList("A", "B", "C");
//              cache.addAll(data);
//        }
//        return cache;
//    }
    public static List<String> selectAll(){
        if(cache.isEmpty()) {//A,B,C,D
            synchronized (cache) {
                if (cache.isEmpty()) {
                    System.out.println("Get Data From Database");
                    List<String> data = Arrays.asList("A", "B", "C");
                    cache.addAll(data);
                }
            }
        }
        return cache;
    }

    public static void main(String[] args) {
        //System.out.println(Thread.currentThread().getName());
        Thread t1=new Thread(){
            @Override
            public void run() {
                System.out.println(selectAll());
            }
        };
        Thread t2=new Thread(){
            @Override
            public void run() {
                System.out.println(selectAll());
            }
        };
        Thread t3=new Thread(){
            @Override
            public void run() {
                System.out.println(selectAll());
            }
        };
        Thread t4=new Thread(){
            @Override
            public void run() {
                System.out.println(selectAll());
            }
        };
        Thread t5=new Thread(){
            @Override
            public void run() {
                System.out.println(selectAll());
            }
        };
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}
package com.jt.provider.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

@RefreshScope
@RestController
public class ProviderCacheController {

    @Value("${useLocalCache:false}")
    private boolean useLocalCache;

    @RequestMapping("/provider/cache")
    public String doUseLocalCache(){
        return "useLocalCache'value is   "+useLocalCache;
    }

    //构建一个本地(Local)缓存对象(基于jvm中的一个对象存储从数据库获取的数据).
    private List<String> cache=new CopyOnWriteArrayList<>();
    @RequestMapping("/provider/cache02")
    public  List<String> doUseLocalCache02(){
        if(!useLocalCache){
            System.out.println("==Get data from database==");
            List<String> cates = Arrays.asList("Category-A", "Category-B", "Category-C");
        }
        if(cache.isEmpty()){
            synchronized (cache) {
                if (cache.isEmpty()) {//Thread-A,Thread-B,...
                    System.out.println("==Get data from database==");
                    //假设这部分分类信息是从数据库获取的,但是,我不希望每次获取分类信息都要从数据库查
                    List<String> cates = Arrays.asList("Category-A", "Category-B", "Category-C");
                    cache.addAll(cates);
                }
            }
        }
        return cache;
    }//生产层面
}

配置中新为false
在这里插入图片描述
实现效果
在这里插入图片描述
在这里插入图片描述
redis分布式缓存
lruCache 本地缓存+分布式缓存

5.Nacos的配置管理模型——共享配置的读取

5.1新建配置

在这里插入图片描述

5.2修改配置文件

在这里插入图片描述

5.3新建Conreoller层

package com.jt.provider.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope
public class ProviderSecretController {
    @Value("${app.secret:123456}")
    private String secret;
    @GetMapping("/provider/doGetSecret")
    public String doGetSecret(){
        return "the secret is"+secret;
    }
}

实现效果
在这里插入图片描述

总结

  • 配置管理模型三要素:namespace( group( dataId
  • 为什么会有共享配置???很多配置中有一些共性
  • 如何理解命名空间???定义一些配置的作用域,做配置的分类管理
  • 为什么进行分组???同一环境下不同活动会有不同配置
  • 如何引用共享配置???使用shared-configs
  • 线程安全问题前提:多个线程+有共享数据集+是否是原子操作
  • 如何理解线程并发中的双重校验锁???性能+安全
  • CopyOnWriteArrayList 线程安全

版权声明:本文为weixin_55740233原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。