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) {
Timer timer=new Timer();
TimerTask task1=new TimerTask() {
@Override
public void run() {
System.out.println(System.currentTimeMillis());
}
};
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) {
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(5);
Runnable runnable=new Runnable() {
@Override
public void run() {
String tName=Thread.currentThread().getName();
System.out.println(tName+"->"+System.currentTimeMillis());
}
};
scheduledExecutorService.
scheduleAtFixedRate(runnable,1000,
1000,
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
config:
server-addr: localhost:8848
file-extension: yml
namespace: 1ec9fffa-c171-458d-815d-502a52daf446
logging:
level:
com.jt: debug
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 CopyOnWriteArrayList<>();
public static List<String> selectAll(){
if(cache.isEmpty()) {
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) {
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;
}
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()) {
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 线程安全
|