配置文件
配置文件
- 在企业开发过程中,我们习惯把一些需要灵活配置的数据放在一些文本文件中,而不是在Java代码写死
- 我们把这种存放程序配置信息的文件,统称为配置文件
配置文件一般要求有明确的格式,以方便读写操作!!!
Properties
什么是Properties?
- 是一个Map集合(键值对集合),但是我们一般不会当集合使用。
- 核心作用:Properties是用来代表属性文件的,通过Properties可以读写属性文件里的内容。
- Properties的作用?
- 可以存储Properties属性集的键值对数据到属性文件中去:
- void store(Writer writer, String comments)
- 可以加载属性文件中的数据到Properties对象中来:
- void load(Reader reader)
- 可以存储Properties属性集的键值对数据到属性文件中去:
使用Properties读取属性文件里的键值对数据
构造器 | 说明 |
---|---|
public Properties() | 用于构建Properties集合对象(空容器) |
常用方法 | 说明 |
---|---|
public void load(InputStream is) | 通过字节输入流,读取属性文件里的键值对数据 |
public void load(Reader reader) | 通过字符输入流,读取属性文件里的键值对数据 |
public String getProperty(String key) | 根据键获取值(其实就是get方法的效果) |
public Set stringPropertyNames() | 获取全部键的集合(其实就是ketSet方法的效果) |
使用Properties把键值对数据写出到属性文件里去
构造器 | 说明 |
---|---|
public Properties() | 用于构建Properties集合对象(空容器) |
常用方法 | 说明 |
---|---|
public Object setProperty(String key, String value) | 保存键值对数据到Properties对象中去。 |
public void store(OutputStream os, String comments) | 把键值对数据,通过字节输出流写出到属性文件里去 |
public void store(Writer w, String comments) | 把键值对数据,通过字符输出流写出到属性文件里去 |
XML
XML是什么?
- 全称Extensible Markup Language, 可扩展标记语言
- 本质是一种数据的格式,可以用来存储复杂的数据结构,和数据关系。
XML的特点
- XML中的“<标签名>” 称为一个标签或一个元素,一般是成对出现的。
- XML中的标签名可以自己定义(可扩展),但必须要正确的嵌套。
- XML中只能有一个根标签。
- XML中的标签可以有属性。
- 如果一个文件中放置的是XML格式的数据,这个文件就是XML文件,后缀一般要写成.xml。
XML语法
XML文件的后缀名为:xml,文档声明必须是第一行
<?xml version="1.0" encoding="UTF-8" ?>
version:XML默认的版本号码、该属性是必须存在的
encoding:本XML文件的编码
XML中可以定义注释信息:<!–- 注释内容 -->,快捷键是Ctrl+shift+/
XML中书写”<”、“&”等,可能会出现冲突,导致报错,此时可以用如下特殊字符替代。
< < 小于
> > 大于
& & 和号
' ' 单引号
" " 引号
XML中可以写一个叫CDATA的数据区: <![CDATA[ …内容… ]]>,里面的内容可以随便写。
XML的作用
- 用于进行存储数据和传输数据
- 作为软件的配置文件
应用场景
- 本质是一种数据格式,可以存储复杂的数据结构,和数据关系。
- 应用场景:经常用来做为系统的配置文件;或者作为一种特殊的数据结构,在网络中进行传输。
XML解析技术
使用程序读取XML文件中的数据
注意:程序员并不需要自己写原始的IO流代码来解析XML,难度较大!也相当繁琐!
其实,有很多开源的,好用的,解析XML的框架,最知名的是:Dom4j(第三方研发的)
DOM4J解析XML文件的思想:文档对象模型
Dom4J的解析思想?
- 得到文档对象Document,从中获取元素对象和内容。
Dom4j解析XML-得到Document对象
SAXReader:Dom4j提供的解析器,可以认为是代表整个Dom4j框架
构造器/方法 | 说明 |
---|---|
public SAXReader() | 构建Dom4J的解析器对象 |
public Document read(String path) | 把XML文件读成Document对象 |
Document
方法名 | 说明 |
---|---|
Element getRootElement() | 获得根元素对象 |
Element提供的方法
方法名 | 说明 |
---|---|
public String getName() | 得到元素名字 |
public List elements() | 得到当前元素下所有子元素 |
public List elements(String name) | 得到当前元素下指定名字的子元素返回集合 |
public Element element(String name) | 得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个 |
public String attributeValue(String name) | 通过属性名直接得到属性值 |
public String elementText(子元素名) | 得到指定名称的子元素的文本 |
public String getText() | 得到文本 |
Dom4J的解析后的数据形式。
- 通常数据会封装成Java的对象,如单个对象,或者集合对象形式。
建议
- 如何使用程序把数据写出到XML文件中去?
- 不建议用 dom4j
- 推荐直接把程序里的数据拼接成XML格式, 然后用IO流写出
XML约束
什么是XML约束
就是限制XML文件只能按照某种格式进行书写。
约束文档分为: DTD Schema文档
XML文档约束-DTD的使用(了解)
需求:利用DTD约束文档,约束一个XML文件的编写。
<!ELEMENT 书架 (书+)> <!ELEMENT 书 (书名,作者,售价)> <!ELEMENT 书名 (#PCDATA)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 售价 (#PCDATA)>
编写DTD约束文档,后缀必须是.dtd在需要编写的XML文件中导入该DTD约束文档
然后XML文件,就必须按照DTD约束文档指定的格式进行编写,否则报错!
作用和问题
- 可以约束XML文件的编写
- 不能约束具体的数据类型
XML文档约束-schema的使用(了解)
可以约束XML文件的编写、和数据类型
- 需求:利用schema文档约束,约束一个XML文件的编写。
- 编写schema约束文档,后缀必须是.xsd,具体的形式到代码中观看。
- 在需要编写的XML文件中导入该schema约束文档
- 按照约束内容编写XML文件的标签。
优点?
- 可以约束XML文件的标签内容格式,以及具体的数据类型。
- 本身也是xml文件,格式更严谨。
XML检索技术:Xpath
Xpath作用,四大类。
- 检索XML文件中的信息
- 绝对路径: /根元素/子元素/孙元素
- 相对路径:./子元素/孙元素
- 全文检索://contact
- 属性查找://@属性名 、//元素[@属性名]、//元素//[@属性名=‘值’]
日志
概述
什么是日志?
- 用来记录程序运行过程中的信息,并可以进行永久存储。
输出语句的弊端
- 日志会展示在控制台
- 不能更方便的将日志记录到其他的位置(文件,数据库)
- 想取消日志,需要修改源代码才可以完成
日志技术
- 可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)。
- 可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改。
体系架构
日志接口
- 日志接口大多是一些规范,用来约束日志实现框架的设计。
- Commons Logging、Simple Logging Facade for Java(slf4j)
日志框架
-
Log4J、Logback(我们重点学习的,其他的都大同小异)。
-
Logback是基于slf4j日志接口实现的日志框架。
-
注意1:因为对Commons Logging接口不满意,有人就搞了SLF4J;因为对Log4j的性能不满意,有人就搞了Logback。
-
注意2:Logback是基于slf4j的日志规范实现的框架。
输出语句存在的问题,日志技术应该具备哪些特点和优势?
输出语句 | 日志技术 | |
---|---|---|
输出位置 | 输出到控制台 | 可以将日志信息写入到文件或者数据库中 |
取消日志 | 需要修改代码,灵活性比较差 | 不需要修改代码,灵活性比较好 |
多线程 | 性能较差 | 性能较好 |
Logback日志框架模版
Logback日志框架有以下几个模块:
- logback-core 01
- 基础模块,是其他两个模块依赖的基础(必须有)
- logback-classic 02
- 基础模块,是其他两个模块依赖的基础(必须有)
- logback-access 03
- 与 Tomcat 和 Jetty 等 Servlet 容器集成,以提供 HTTP 访问日志的功能(可选,以后再接触)
想使用Logback日志框架,至少需要在项目中整合如下三个模块:
- slf4j-api:日志接口
- logback-core:基础模块
- logback-classic:功能模块,它完整实现了slf4j API
常见的日志实现框架有哪些?
- Log4J、Logback(我们重点学习的,其他的都大同小异)
- Logback是基于slf4j日志接口实现的日志框架
Logback快速入门
步骤
需求
l使用Logback日志框架,纪录系统的运行信息。
实现步骤
- 在项目下新建文件夹lib,导入Logback的相关jar包到该文件夹下,并添加到项目库中去。
导入Logback框架到项目中去。
- slf4j-api:日志接口
- logback-core
- logback-classic
- 将Logback框架的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)。
- 创建Logback框架提供的Logger对象,然后用Logger对象调用其提供的方法就可以记录系统的日志信息。
public static final Logger LOGGER = LoggerFactory.getLogger("当前类类名");
- 调用日志对象的方法记录日志信息
核心配置文件logback.xml
对Logback日志框架进行控制的。
日志的输出位置、输出格式的设置
通常可以设置2个输出日志的位置: 一个是控制台、一个是系统文件中
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> // 输出到控制台的配置标志
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> // 输出到系统文件的配置标志
开启日志(ALL),取消日志(OFF)
<root level="ALL">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE" />
</root>
Logback设置日志级别
什么是日志级别
日志级别指的是日志信息的类型,日志都会分级别,常见的日志级别如下(优先级依次升高):
日志级别 | 说明 |
---|---|
trace | 追踪,指明程序运行轨迹 |
debug | 调试,实际应用中一般将其作为最低级别,而 trace 则很少使用 |
info | 输出重要的运行信息,数据连接、网络连接、IO操作等等,使用较多 |
warn | 警告信息,可能会发生问题,使用较多 |
error | 错误信息, 使用较多 |
设置日志输出级别的作用是什么?
- 用于控制系统中哪些日志级别是可以输出的。
Logback的日志级别是什么样的?
- ALL 和OFF分别是打开全部日志和关闭全部日志
- 级别程度依次是: TRACE< DEBUG< INFO<WARN<ERROR
- 默认级别是debug (忽路大闯.只输出当前级别及高于该级别的日志
为什么学习日志级别
<root level=“info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE" />
</root>
只有日志的级别是大于或等于核心配置文件配置的日志级别,才会被记录,否则不记录。
多线程
多线程介绍
什么是线程?
- 线程:简单的说,就是计算机在做一件事
- 单线程:在计算机中同一时间只能做一件事
- 多线程:在计算机中同一时间可以做多件事
好处
- 减少队列阻塞带来的影响
- 提高CPU的利用率
应用
- 线程(thread)是一个程序内部的一条执行路径。
- 我们之前启动程序执行后,main方法的执行其实就是一条单独的执行路径。
public static void main(String[] args) {
// 代码…
for (int i = 0; i < 10; i++) { System.out.println(i); }
// 代码...
}
程序中如果只有一条执行路径,那么这个程序就是单线程的程序。
多线程的创建
创建方式一:
- 定义一个子类继承线程类java.lang.Thread,重写run()方法
- 创建子类的对象
- 调用子类对象的start()方法启动线程(底层会自动去执行run方法)
优缺点?
- 优点:编码简单
- 缺点:存在单继承的局限性,线程类继承Thread后,不能继承其他类,不便于扩展。
- 启动线程必须是调用start方法,不是调用run方法。
- 不要把主线程任务放在启动子线程之前。
- 直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。
- 只有调用start方法才是启动一个新的线程执行。
- 这样主线程一直是先跑完的,相当于是一个单线程的效果了。
创建方式二: 实现Runnable接口
- 定义一个线程任务类实现Runnable接口,重写run()方法
- 创建任务类对象
- 把任务类对象交给Thread处理
public Thread(Runnable target)
: 封装Runnable对象成为线程对象- 调用线程对象的start()方法启动线程
优缺点:
- 优点:线程任务类只是实现了Runnale接口,可以继续继承和实现。
任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。 - 缺点:如果线程有执行结果是不能直接返回的。需要多一个Runnable对象。
创建方式二的匿名内部类写法
可以创建Runnable的匿名内部类对象。
再交给Thread线程对象。
再调用线程对象的start()启动线程。
前两种方式总结
前两种线程创建方式都存在的一个问题
- 假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果。
解决方式
- JDK 5.0提供了Callable接口和FutureTask类来实现(多线程的第三种创建方式)。
- 这种方式最大的优点:可以返回线程执行完毕后的结果。
创建方式三:利用Callable接口、FutureTask类来实现
- 创建任务对象
- 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据。
- 把Callable类型的对象封装成FutureTask(线程任务对象)。
- 把线程任务对象交给Thread对象。
- 调用Thread对象的start方法启动线程。
- 线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果。
FutureTask的API
FutureTask提供的构造器 | 说明 |
---|---|
public FutureTask<>(Callable call) | 把Callable对象封装成FutureTask对象。 |
FutureTask提供的方法 | 说明 |
---|---|
public V get() throws Exception | 获取线程执行call方法返回的结果。 |
优缺点
- **优点:**线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果。
- **缺点:**编码复杂一点。
3种线程方式对比
方式 | 优点 | 缺点 |
---|---|---|
继承Thread类 | 编程比较简单,可以直接使用Thread类中的方法 | 扩展性较差,不能再继承其他的类,不能返回线程执行的结果 |
实现Runnable接口 | 扩展性强,实现该接口的同时还可以继承其他的类。 | 编程相对复杂,不能返回线程执行的结果 |
实现Callable接口 | 扩展性强,实现该接口的同时还可以继承其他的类。可以得到线程执行的结果 | 编程相对复杂 |
Thread的方法
Thread常用方法
方法名称 | 说明 |
---|---|
String getName() | 获取当前线程的名称,默认线程名称是Thread-索引 |
void setName(String name) | 设置线程名称 |
public static Thread currentThread(): | 返回对当前正在执行的线程对象的引用 |
public static void sleep(long time) | 让线程休眠指定的时间,单位为毫秒。 |
public void run() | 线程任务方法 |
public void start() | 线程启动方法 |
public final void join()… | 让调用当前这个方法的线程先执行完! |
Thread构造器
构造器 | 说明 |
---|---|
public Thread(String name) | 可以为当前线程指定名称 |
public Thread(Runnable target) | 把Runnable对象交给线程对象 |
public Thread(Runnable target ,String name ) | 把Runnable对象交给线程对象,并指定线程名称 |