1 相关知识点
1.1日志级别
日志记录是软件开发的一个概念,几乎开发项目都能从日志记录中知道程序的运行是否正常,运行时的异常处于程序的哪个部分。日志级别是对基本的“滚动文本”式日志记录的一个重要补充。每条日志消息都会基于其重要性或严重程度分配到一个日志级别。在我们使用的日志级别中,log4j是一个极为重要且常用的日志级别规范》
官方网址: http://logging.apache.org/log4j/1.2/
其主要有以下一些级别构成,各个级别的输出的内容有所不同
ALL(输出所有类型日志)
DEBUG (输出DEBUG 以上级别日志)
INFO(输出INFO以上级别日志)
WARA(输出WARA以上级别日志)
ERROR (输出ERROR 以上级别日志)
FATAL (输出FATAL 以上级别日志)
OFF (关闭日志输出)
日志级别顺序:ALL<DEBUG <INFO<WARA<ERROR <FATAL <OFF
log.trace("==log.trace==");//跟踪
log.debug("==log.debug==");//调试
log.info("==log.info==");//常规信息
log.warn("==log.warn==");//警告
log.error("==log.error==");//错误信息
具体在输出时顺序会输入对应界别以上的日志信息,如定义debug,则日志中会输出info,warn,error级别日志信息
1.2配置中心
配置中心最基础的功能就是存储一个键值对,用户发布一个配置(configKey),然后客户端获取这个配置项(configValue);进阶的功能就是当某个配置项发生变更时,不停机就可以动态刷新服务内部的配置项,例如,在生产环境上我们可能把我们的日志级别调整为 error 级别,但是,在系统出问题我们希望对它 debug 的时候,我们需要动态的调整系统的行为的能力,把日志级别调整为 debug 级别。配置中心就是在此背景下诞生,通过配置中心可以便捷的修改项目的一些配置。 图中所示的nacos-server就是nacos的配置中心,其可以配置yml和propery的信息,以便捷的完成参数的修改。
目前市场上主流配置中心有Apollo(携程开源),nacos(阿里开源),Spring Cloud Config(Spring Cloud 全家桶成员)。我们在对这些配置中心进行选型时重点要从产品功能、使用体验、实施过程和性能等方面进行综合考量。本次课程我们选择nacos,此组件不仅提供了注册中心,还具备配置中心的功能。
2.Naccos配置入门
2.1添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2.2修改配置文件
spring:
application:
name: sca-provider
cloud:
nacos:
discovery: #注册中心
server-addr: 127.0.0.1:8848
config: #配置中心
server-addr: 127.0.0.1:8848
group: DEFAULT_GROUP # Group, default is DEFAULT_GROUP
file-extension: yml #
2.3nacos基本配置
说明:此配置配置的是java系统中的日志级别
2.4 Controller处理器操作---获取日志级别的方法
@RefreshScope //动态刷新配置
@RestController
public class ProviderController{
private static final Logger log=
LoggerFactory.getLogger(ProviderApplication.class);
@Value("${logging.level.com.jt:error}")
private String logLevel;
@GetMapping("/provider/doGetLogLevel")
public String doGetLogLevel(){
log.trace("==log.trace==");//跟踪
log.debug("==log.debug==");//调试
log.info("==log.info==");//常规信息
log.warn("==log.warn==");//警告
log.error("==log.error==");//错误信息
return "log level is "+logLevel;
}
}
2.5 查看配置信息
2.6 Nacos配置动态更新实现
新建配置设置
配置实现:
3.配置中心进阶
3.1Nacos配置管理模型
Nacos 配置管理模型由三部分构成,如图所示:
其中:
- Namespace:命名空间,对不同的环境进⾏隔离,⽐如隔离开发环境和⽣产环境。
- Group:分组,将若⼲个服务或者若⼲个配置集归为⼀组。
- Service/DataId:某⼀个服务或配置集,一般对应一个配置文件。
命名空间基本操作
新建———克隆或添加配置——添加命名空间配置
spring:
cloud:
nacos:
config:
namespace: 6058fd3f-0d4d-44f2-85d6-5fc7d2348046
#idea中配置的命名空间,组id,名字要一一对应
3.2 分组实现
1.新建配置时指定分组名称,修改配置
说明:配置的内容是设定线程池的最大值
2.修改boostrap.yml配置类,在其内部指定我们刚刚创建的分组
server-addr: 127.0.0.1:8848
group: DEV_GROUP_51 # Group, d
file-extension: yml #
namespace: 5c27fe4a-1141-4836-a14e-cbac77fb2130
3.控制层输入代码
@Value("${server.tomcat.threads.max:200}")
private Integer maxThread;
@RequestMapping("/provider/doGetMaxThread")
public String doGetMaxThread(){
return "server.threads.max is "+maxThread;
}
4.执行时优先执行控制层配置,之后再远程调用配置中心配置,实现程序运行,具体操作如下
3.3.共享配置创建
1.远程配置
2.共享配置
# 共享配置
shared-configs[0]:
data-id: app-public-dev.yml
group: DEFAULT_GROUP
refresh: true #默认false
3。代码测试
@Value("${page.pageSize:10}")
private Integer pageSize;
@GetMapping("/provider/doGetPageSize")
public String doGetPageSize(){
//return String.format()
return "page size is "+pageSize;
}
4.测试结果
3.4 总结
nacos配置的关键在于配置文件的一些经常变动的参数,如线程池的最大值,日志级别,分页的规模等相关的一些配置操作,其本质是集成各方的功能,将可变的参数统一到一个地方,以便于方便的管理。在调用过程中,nacos会优先读取配置文件类的配置,然后找到配置中心信息,进行拉取刷新操作,也从而使得nacos有优于tomcat的高并发性能.
nacos获取配置信息图解
读取文件的优先顺序如图:
nacos配置中心管理的底层结构是一个三层结构,通过不同的命名空间,组和dataid,能够极为方便的管理众多的配置文件,底层结构如下图;
4 面试题以及相关小知识点
4.1面试知识
- 配置中心的选型。(市场活跃度、稳定性、性能、易用)
- Nacos配置中心基本应用。(新建,修改、删除配置以后,在Nacos客户端应用配置)
- 配置管理模型应用。(namespace,group,service/dataId)
- Nacos配置变更的动态感知。(底层原理分析)
4.2 线程池入门
1.线程池构成
2.线程池执行顺序
3.线程池测试
public class ThreadPoolTests {
public static void main(String[] args) {
int corePoolSize=2;
int maximumPoolSize=3;
long keepAliveTime=60;
TimeUnit unit=TimeUnit.SECONDS;
//5
BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue<Runnable>(5);
//6创建线程池
ThreadPoolExecutor pool =new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue
);
//7任务测试
pool.execute(new Runnable() {
public void run() {
String tName=Thread.currentThread().getName();
System.out.println(tName+"->任务1");
try{Thread.sleep(5000);}catch (Exception e){ }
}
});
pool.execute(new Runnable() {
public void run() {
String tName=Thread.currentThread().getName();
System.out.println(tName+"->任务2");
try{Thread.sleep(5000);}catch (Exception e){ }
}
});
pool.execute(new Runnable() {
public void run() {
String tName=Thread.currentThread().getName();
System.out.println(tName+"->任务3");
try{Thread.sleep(5000);}catch (Exception e){ }
}
});
pool.execute(new Runnable() {
public void run() {
String tName=Thread.currentThread().getName();
System.out.println(tName+"->任务4");
try{Thread.sleep(5000);}catch (Exception e){ }
}
});
pool.execute(new Runnable() {
public void run() {
String tName=Thread.currentThread().getName();
System.out.println(tName+"->任务5");
try{Thread.sleep(1000);}catch (Exception e){ }
}
});
}
}
测试结果
线程池满异常