09 配置文件&日志&多线程

本文介绍了配置文件的使用,特别是Properties类及其在Java中的应用,详细讲解了XML(包括DTD和Schema)在数据存储和传输中的角色,以及DOM4J解析XML的方法。同时,文章还讨论了日志技术,尤其是Logback框架的使用,以及多线程编程中的Callable和FutureTask接口。
摘要由CSDN通过智能技术生成

配置文件

配置文件

  • 在企业开发过程中,我们习惯把一些需要灵活配置的数据放在一些文本文件中,而不是在Java代码写死
  • 我们把这种存放程序配置信息的文件,统称为配置文件

配置文件一般要求有明确的格式,以方便读写操作!!!

image-20240414082438140

Properties

image-20240414082744207

什么是Properties?

  • 是一个Map集合(键值对集合),但是我们一般不会当集合使用。
  • 核心作用:Properties是用来代表属性文件的,通过Properties可以读写属性文件里的内容。
  • Properties的作用?
    • 可以存储Properties属性集的键值对数据到属性文件中去:
      • void store(Writer writer, String comments)
    • 可以加载属性文件中的数据到Properties对象中来:
      • void load(Reader reader)

使用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中书写”<”、“&”等,可能会出现冲突,导致报错,此时可以用如下特殊字符替代。

&lt;    <  小于
&gt;    >  大于
&amp;   &  和号
&apos;  '  单引号
&quot;  "  引号

XML中可以写一个叫CDATA的数据区: <![CDATA[   …内容…  ]]>,里面的内容可以随便写。

XML的作用
  • 用于进行存储数据和传输数据
  • 作为软件的配置文件
应用场景
  • 本质是一种数据格式,可以存储复杂的数据结构,和数据关系。
  • 应用场景:经常用来做为系统的配置文件;或者作为一种特殊的数据结构,在网络中进行传输。
XML解析技术

使用程序读取XML文件中的数据

注意:程序员并不需要自己写原始的IO流代码来解析XML,难度较大!也相当繁琐!

其实,有很多开源的,好用的,解析XML的框架,最知名的是:Dom4j(第三方研发的)

DOM4J解析XML文件的思想:文档对象模型

image-20240414085846935

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文件只能按照某种格式进行书写。

image-20240414091403847

约束文档分为: DTD Schema文档

XML文档约束-DTD的使用(了解)

需求:利用DTD约束文档,约束一个XML文件的编写。
编写DTD约束文档,后缀必须是.dtd

<!ELEMENT 书架 (书+)> <!ELEMENT 书 (书名,作者,售价)> <!ELEMENT 书名 (#PCDATA)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 售价 (#PCDATA)>

在需要编写的XML文件中导入该DTD约束文档

然后XML文件,就必须按照DTD约束文档指定的格式进行编写,否则报错!

作用和问题

  • 可以约束XML文件的编写
  • 不能约束具体的数据类型
XML文档约束-schema的使用(了解)

可以约束XML文件的编写、和数据类型

  • 需求:利用schema文档约束,约束一个XML文件的编写。
  • 编写schema约束文档,后缀必须是.xsd,具体的形式到代码中观看。
  • 在需要编写的XML文件中导入该schema约束文档
  • 按照约束内容编写XML文件的标签。

优点?

  • 可以约束XML文件的标签内容格式,以及具体的数据类型。
  • 本身也是xml文件,格式更严谨。

XML检索技术:Xpath

Xpath作用,四大类。

  • 检索XML文件中的信息
  • 绝对路径: /根元素/子元素/孙元素
  • 相对路径:./子元素/孙元素
  • 全文检索://contact
  • 属性查找://@属性名 、//元素[@属性名]、//元素//[@属性名=‘值’]

日志

概述

什么是日志?

  • 用来记录程序运行过程中的信息,并可以进行永久存储。

输出语句的弊端

  • 日志会展示在控制台
  • 不能更方便的将日志记录到其他的位置(文件,数据库)
  • 想取消日志,需要修改源代码才可以完成
日志技术
  • 可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)。
  • 可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改。
体系架构
image-20240414104100582

日志接口

  • 日志接口大多是一些规范,用来约束日志实现框架的设计。
  • Commons Logging、Simple Logging Facade for Java(slf4j)

日志框架

  • Log4J、Logback(我们重点学习的,其他的都大同小异)。

  • Logback是基于slf4j日志接口实现的日志框架。

  • 注意1:因为对Commons Logging接口不满意,有人就搞了SLF4J;因为对Log4j的性能不满意,有人就搞了Logback。

  • 注意2:Logback是基于slf4j的日志规范实现的框架。

输出语句存在的问题,日志技术应该具备哪些特点和优势

输出语句日志技术
输出位置输出到控制台可以将日志信息写入到文件或者数据库中
取消日志需要修改代码,灵活性比较差不需要修改代码,灵活性比较好
多线程性能较差性能较好

Logback日志框架官方网站:

Logback日志框架模版

Logback日志框架有以下几个模块:

  • logback-core 01
    • 基础模块,是其他两个模块依赖的基础(必须有)
  • logback-classic 02
    • 基础模块,是其他两个模块依赖的基础(必须有)
  • logback-access 03
    • 与 Tomcat 和 Jetty 等 Servlet 容器集成,以提供 HTTP 访问日志的功能(可选,以后再接触)

想使用Logback日志框架,至少需要在项目中整合如下三个模块:

  1. slf4j-api:日志接口
  2. logback-core:基础模块
  3. logback-classic:功能模块,它完整实现了slf4j API

常见的日志实现框架有哪些?

  • Log4J、Logback(我们重点学习的,其他的都大同小异)
  • Logback是基于slf4j日志接口实现的日志框架

Logback快速入门

步骤

需求

l使用Logback日志框架,纪录系统的运行信息。

实现步骤

  1. 在项目下新建文件夹lib,导入Logback的相关jar包到该文件夹下,并添加到项目库中去。
    导入Logback框架到项目中去。
    • slf4j-api:日志接口
    • logback-core
    • logback-classic
  2. 将Logback框架的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)。
  3. 创建Logback框架提供的Logger对象,然后用Logger对象调用其提供的方法就可以记录系统的日志信息。
    • public static final Logger LOGGER = LoggerFactory.getLogger("当前类类名");
  4. 调用日志对象的方法记录日志信息
核心配置文件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的利用率

应用

image-20240414141929635

  • 线程(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后,不能继承其他类,不便于扩展。
  1. 启动线程必须是调用start方法,不是调用run方法。
  2. 不要把主线程任务放在启动子线程之前。
  • 直接调用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类来实现
  1. 创建任务对象
    • 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据。
    • 把Callable类型的对象封装成FutureTask(线程任务对象)。
  2. 把线程任务对象交给Thread对象。
  3. 调用Thread对象的start方法启动线程。
  4. 线程执行完毕后、通过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对象交给线程对象,并指定线程名称
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

InnovatorX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值