11 基础加强(类加载器/反射/xml/DTD/schema/枚举/注解/单元测试/日志)

118 阅读17分钟

#博学谷IT学习技术支持#

11-1 类加载器

01-类加载器-了解

负责将.class文件(存储的物理文件)加载在到内存中

02-类加载器-类加载时机

  • 类加载时机 创建类的实例(对象)
    • 调用类的类方法
    • 访问类或者接口的类变量,或者为该类变量赋值
    • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对初始化某个类的子类
    • 直接使用java.exe命令来运行某个主类

03-类加载的过程-加载+链接

  • 类加载过程
      1. 加载
      • 通过包名 + 类名,获取这个类,准备用流进行传输
      • 在这个类加载到内存中
      • 加载完毕创建一个class对象

    1. 链接
    • 验证

确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身 安全(文件中的信息是否符合虚拟机规范有没有安全隐患)

  • 准备
    • 负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值 (初始化静态变量)

  • 解析
    • 将类的二进制数据流中的符号引用替换为直接引用 (本类中如果用到了其他类,此时就需要找到对应的类)

  • 初始化

    • 根据程序员通过程序制定的主观计划去初始化类变量和其他资源 (静态变量赋值以及初始化其他资源)

05-类加载的过程-初始化和小结

  • 小结
    • 当一个类被使用的时候,才会加载到内存
    • 类加载的过程: 加载、验证、准备、解析、初始化

06-类加载器-分类

  • 分类

    • Bootstrap class loader:虚拟机的内置类加载器,通常表示为null ,并且没有父null
    • Platform class loader:平台类加载器,负责加载JDK中一些特殊的模块
    • System class loader:系统类加载器,负责加载用户类路径上所指定的类库
  • 类加载器的继承关系

    • System的父加载器为Platform
    • Platform的父加载器为Bootstrap
  public class ClassLoaderDemo1 {
      public static void main(String[] args) {
          //获取系统类加载器
          ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
          //获取系统类加载器的父加载器 --- 平台类加载器
          ClassLoader classLoader1 = systemClassLoader.getParent();
          //获取平台类加载器的父加载器 --- 启动类加载器
          ClassLoader classLoader2 = classLoader1.getParent();
          System.out.println("系统类加载器" + systemClassLoader);
          System.out.println("平台类加载器" + classLoader1);
          System.out.println("启动类加载器" + classLoader2);
      }
  }

07-类加载器-双亲委派模型

介绍

如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载 器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达 顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完 成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式

08-类加载器-常用方法

  public class ClassLoaderDemo2 {
      public static void main(String[] args) throws IOException {
          //static ClassLoader getSystemClassLoader() 获取系统类加载器
          //InputStream getResourceAsStream(String name)  加载某一个资源文件
          //获取系统类加载器
          ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
          //利用加载器去加载一个指定的文件
          //参数:文件的路径(放在src的根目录下,默认去那里加载)
          //返回值:字节流。
          InputStream is = systemClassLoader.getResourceAsStream("prop.properties");
          Properties prop = new Properties();
          prop.load(is);
          System.out.println(prop);
          is.close();
      }
  }

11-2 反射

09-反射-概述

反射机制

是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意属性和方法; 这种动态获取信息以及动态调用对象方法的功能称为Java语言 的反射机制。

10-反射-获取class对象

  • 三种方式分类
    • 类名.class属性
    • 对象名.getClass()方法
    • Class.forName(全类名)方法

11-反射-获取Constructor对象

12-反射-利用Constructor创建对象

13-反射-小结

  • 获取class对象
    • 三种方式: Class.forName(“全类名”), 类名.class, 对象名.getClass()
  • 获取里面的构造方法对象
    • getConstructor (Class... parameterTypes) getDeclaredConstructor (Class... parameterTypes)
  • 如果是public的,直接创建对象
    • newInstance(Object... initargs)
  • 如果是非public的,需要临时取消检查,然后再创建对象
    • setAccessible(boolean) 暴力反射

14-反射-获取Field对象

15-反射-利用Field赋值和获取值

16-反射-获取Method对象

17-反射-利用Method对象运行方法

参数一: 用obj对象调用该方法

参数二: 调用方法的传递的参数(如果没有就不写)

返回值: 方法的返回值(如果没有就不写)

11-4 xml

01-xml-作为配置文件的优势

可读性好 可维护性高

02-xml-概述

XML的全称为(EXtensible Markup Language),是一种可扩展的标记语言 标记语言: 通过标签来描述 数据的一门语言(标签有时我们也将其称之为元素) 可扩展:标签的名字是可以自定义的,XML文件是 由很多标签组成的,而标签名是可以自定义的

03-xml-标签的规则

  • 标签由一对尖括号和合法标识符组成 <student>

  • 标签必须成对出现 <student> </student>

  • 特殊的标签可以不成对,但是必须有结束标记 <address/>

  • 标签中可以定义属性,属性和标签名空格隔开,属性值必须用引号引起来

    • <student id="1"> </student>
  • 标签需要正确的嵌套

04-xml-语法规则

  • XML文件的后缀名为:xml
  • 文档声明必须是第一行第一列
    • version:该属性是必须存在的
    • encoding:该属性不是必须的 打开当前xml文件的时候应该是使用什么字符编码表(一般取值都是UTF-8)
    • standalone: 该属性不是必须的,描述XML文件是否依赖其他的xml文件,取值为yes/no
  • 必须存在一个根标签,有且只能有一个
  • XML文件中可以定义注释信息
  • XML文件中可以存在以下特殊字符
&lt; < 小于
&gt; > 大于
&amp; & 和号
&apos; ' 单引号
&quot; " 引号
  • XML文件中可以存在CDATA区
  • 示例:
  <?xml version="1.0" encoding="UTF-8" ?>
  <!--注释的内容-->
  <!--本xml文件用来描述多个学生信息-->
  <students>

      <!--第一个学生信息-->
      <student id="1">
          <name>张三</name>
          <age>23</age>
          <info>学生&lt; &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;的信息</info>
          <message> <![CDATA[内容 <<<<<< >>>>>> ]]]></message>
      </student>

      <!--第二个学生信息-->
      <student id="2">
          <name>李四</name>
          <age>24</age>
      </student>
  </students>

05-xml-DOM解析思想

DOM(Document Object Model)文档对象模型:就是把文档的各个组成部分看做成对应的对象。 会把 xml文件全部加载到内存,在内存中形成一个树形结构,再获取对应的值

06-xml-解析

  • 常见的解析工具
    • JAXP: SUN公司提供的一套XML的解析的API
    • JDOM: 开源组织提供了一套XML的解析的API-jdom
    • DOM4J: 开源组织提供了一套XML的解析的API-dom4j,全称:Dom For Java
    • pull: 主要应用在Android手机端解析XML
  • 解析的准备工作
    • 可以通过网站:dom4j.github.io/ 去下载dom4j
    • 将提供好的dom4j-1.6.1.zip解压,找到里面的dom4j-1.6.1.jar
    • 在idea中当前模块下新建一个libs文件夹,将jar包复制到文件夹中
    • 选中jar包 -> 右键 -> 选择add as library即可
  /**
   * 利用dom4j解析xml文件
   */
  public class XmlParse {
      public static void main(String[] args) throws DocumentException {
          //1.获取一个解析器对象
          SAXReader saxReader = new SAXReader();
          //2.利用解析器把xml文件加载到内存中,并返回一个文档对象
          Document document = saxReader.read(new File("myxml\xml\student.xml"));
          //3.获取到根标签
          Element rootElement = document.getRootElement();
          //4.通过根标签来获取student标签
          //elements():可以获取调用者所有的子标签.会把这些子标签放到一个集合中返回.
          //elements("标签名"):可以获取调用者所有的指定的子标签,会把这些子标签放到一个集合中并返回
          //List list = rootElement.elements();
          List<Element> studentElements = rootElement.elements("student");
          //System.out.println(list.size());

          //用来装学生对象
          ArrayList<Student> list = new ArrayList<>();
          //5.遍历集合,得到每一个student标签
          for (Element element : studentElements) {
              //element依次表示每一个student标签
              //获取id这个属性
              Attribute attribute = element.attribute("id");
              //获取id的属性值
              String id = attribute.getValue();

              //获取name标签
              //element("标签名"):获取调用者指定的子标签
              Element nameElement = element.element("name");
              //获取这个标签的标签体内容
              String name = nameElement.getText();

              //获取age标签
              Element ageElement = element.element("age");
              //获取age标签的标签体内容
              String age = ageElement.getText();

              Student s = new Student(id,name,Integer.parseInt(age));
              list.add(s);
          }
          //遍历操作
          for (Student student : list) {
              System.out.println(student);
          }
      }
  }

11-5 DTD

08-DTD入门

  • 什么是约束
    • 用来限定xml文件中可使用的标签以及属性
  • 约束的分类
    • DTD
    • schema
  • 编写DTD约束
    • 步骤
        1. 创建一个文件,这个文件的后缀名为.dtd
        1. 看xml文件中使用了哪些元素 可以定义元素
        1. 判断元素是简单元素还是复杂元素
        • 简单元素:没有子元素。 复杂元素:有子元素的元素;
<!ELEMENT persons (person)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>

09-DTD入门案例-引入DTD

  • 引入DTD约束的三种方法
    • 引入本地dtd
    • 在xml文件内部引入
    • 引入网络dtd

10-DTD约束-三种引入方式

  • 代码实现
    • 引入本地DTD约束
  // 这是persondtd.dtd文件中的内容,已经提前写好
  <!ELEMENT persons (person)>
  <!ELEMENT person (name,age)>
  <!ELEMENT name (#PCDATA)>
  <!ELEMENT age (#PCDATA)>

  // 在person1.xml文件中引入persondtd.dtd约束

  <?xml version="1.0" encoding="UTF-8" ?>
  <!DOCTYPE persons SYSTEM 'persondtd.dtd'>
  <persons>
      <person>
          <name>张三</name>
          <age>23</age>
      </person>
  </persons>
  • 在xml文件内部引入
  <?xml version="1.0" encoding="UTF-8" ?>

  <!DOCTYPE persons [
          <!ELEMENT persons (person)>
          <!ELEMENT person (name,age)>
          <!ELEMENT name (#PCDATA)>
          <!ELEMENT age (#PCDATA)>
          ]>


  <persons>
      <person>
          <name>张三</name>
          <age>23</age>
      </person>
  </persons>
  • 引入网络dtd
  <?xml version="1.0" encoding="UTF-8" ?>
  <!DOCTYPE persons PUBLIC "dtd文件的名称" "dtd文档的URL">

  <persons>
      <person>
          <name>张三</name>
          <age>23</age>
      </person>
  </persons>

11-DTD语法规则-定义元素

12-DTD语法规则-定义属性

  • 定义一个属性的格式为:
  • 属性的类型:
    • CDATA类型:普通的字符串
  • 属性的约束:
    • // #REQUIRED: 必须的
    • // #IMPLIED: 属性不是必需的
    • // #FIXED value:属性值是固定的
<!ELEMENT persons (person+)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ATTLIST person id CDATA #REQUIRED>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE persons SYSTEM 'persondtd.dtd'>

<persons>
    <person id="001">
        <name>张三</name>
        <age>23</age>
    </person>

    <person id = "002">
        <name>张三</name>
        <age>23</age>
    </person>

</persons>

11-6 schema

13-schema-schema和dtd的区别

  1. schema约束文件也是一个xml文件,符合xml的语法,这个文件的后缀名.xsd

  2. 一个xml中可以引用多个schema约束文件,多个schema使用名称空间区分(名称空间类似于 java包名)

  3. dtd里面元素类型的取值比较单一常见的是PCDATA类型,但是在schema里面可以支持很多个 数据类型

  4. schema 语法更加的复杂

14-schema入门案例-编写schema

1,创建一个文件,这个文件的后缀名为.xsd。

2,定义文档声明

3,schema文件的根标签为:

4,在中定义属性:

xmlns=www.w3.org/2001/XMLSch…

5,在中定义属性 :

targetNamespace =唯一的url地址,指定当前这个schema文件的名称空间。

6,在中定义属性 :

elementFormDefault="qualified“,表示当前schema文件是一个质量良好的文件。

7,通过element定义元素

8,判断当前元素是简单元素还是复杂元素

<?xml version="1.0" encoding="UTF-8" ?>

<schema
    xmlns="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.itheima.cn/javase"
    elementFormDefault="qualified"
>

    <!--定义persons复杂元素-->
    <element name="persons">
        <complexType>
            <sequence>
                <!--定义person复杂元素-->
                <element name = "person">
                    <complexType>
                        <sequence>
                            <!--定义name和age简单元素-->
                            <element name = "name" type = "string"></element>
                            <element name = "age" type = "string"></element>
                        </sequence>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>

15-schema入门案例-引入schema

1,在根标签上定义属性xmlns="www.w3.org/2001/XMLSch…"

2,通过xmlns引入约束文件的名称空间

3,给某一个xmlns属性添加一个标识,用于区分不同的名称空间

格式为: xmlns:标识=“名称空间地址” ,标识可以是任意的,但是一般取值都是xsi

4,通过xsi:schemaLocation指定名称空间所对应的约束文件路径

格式为:xsi:schemaLocation = "名称空间url 文件路径“

<?xml version="1.0" encoding="UTF-8" ?>

<persons
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.itheima.cn/javase"
    xsi:schemaLocation="http://www.itheima.cn/javase person.xsd"
>
    <person>
        <name>张三</name>
        <age>23</age>
    </person>
</persons>

16-schema入门案例-定义属性

    <?xml version="1.0" encoding="UTF-8" ?>
    <schema
        xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.itheima.cn/javase"
        elementFormDefault="qualified"
    >
        <!--定义persons复杂元素-->
        <element name="persons">
            <complexType>
                <sequence>
                    <!--定义person复杂元素-->
                    <element name = "person">
                        <complexType>
                            <sequence>
                                <!--定义name和age简单元素-->
                                <element name = "name" type = "string"></element>
                                <element name = "age" type = "string"></element>
                            </sequence>
                            <!--定义属性,required( 必须的)/optional( 可选的)-->
                            <attribute name="id" type="string" use="required"></attribute>
                        </complexType>
                    </element>
                </sequence>
            </complexType>
        </element>
    </schema>

    <?xml version="1.0" encoding="UTF-8" ?>
    <persons
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.itheima.cn/javase"
        xsi:schemaLocation="http://www.itheima.cn/javase person.xsd"
    >
        <person id="001">
            <name>张三</name>
            <age>23</age>
        </person>
    </persons>

11-8 枚举

21-枚举-什么是枚举

为了间接的表示一些固定的值,Java就给我们提供了枚举 是指将变量的值一一列出来,变量的值只限于 列举出来的值的范围内

22-枚举-定义格式

  public enum s {   
          枚举项1,枚举项2,枚举项3;
  }

  注意: 定义枚举类要用关键字enum
  // 定义一个枚举类,用来表示春,夏,秋,冬这四个固定值
  public enum Season {
      SPRING,SUMMER,AUTUMN,WINTER;
  }

23-枚举-枚举的特点

1.所有枚举类都是Enum的子类

2.我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项

3.每一个枚举项其实就是该枚举的一个对象

4.枚举也是一个类,也可以去定义成员变量

5.枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,

但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略

6.枚举类可以有构造器,但必须是private的,它默认的也是private的。

枚举项的用法比较特殊:枚举("");

7.枚举类也可以有抽象方法,但是枚举项必须重写该方法

  public enum Season {
      SPRING("春"){
          //如果枚举类中有抽象方法
          //那么在枚举项中必须要全部重写
          @Override
          public void show() {
              System.out.println(this.name);
          }
      },
      SUMMER("夏"){
          @Override
          public void show() {
              System.out.println(this.name);
          }
      },
      AUTUMN("秋"){
          @Override
          public void show() {
              System.out.println(this.name);
          }
      },
      WINTER("冬"){
          @Override
          public void show() {
              System.out.println(this.name);
          }
      };
      public String name;
      //空参构造
      //private Season(){}
      //有参构造
      private Season(String name){
          this.name = name;
      }
      //抽象方法
      public abstract void show();
  }

  public class EnumDemo {
      public static void main(String[] args) {
          //第二个特点的演示
          //我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项
          System.out.println(Season.SPRING);
          //第三个特点的演示
          //每一个枚举项其实就是该枚举的一个对象
          Season spring = Season.SPRING;
      }
  }

24-枚举-枚举的方法

  public enum Season {
      SPRING,SUMMER,AUTUMN,WINTER;
  }

  public class EnumDemo {
      public static void main(String[] args) {
  //        String name() 获取枚举项的名称
          String name = Season.SPRING.name();
          System.out.println(name);
  //        int ordinal() 返回枚举项在枚举类中的索引值
          int index1 = Season.SPRING.ordinal();
          System.out.println(index1);
  //        int compareTo(E o) 比较两个枚举项,返回的是索引值的差值
          int result = Season.SPRING.compareTo(Season.WINTER);
          System.out.println(result);//-3
          System.out.println("-----------------------------");
  //        String toString()   返回枚举常量的名称
          String s = Season.SPRING.toString();
          System.out.println(s);
  //        static <T> T valueOf(Class<T> type,String name
  //        获取指定枚举类中的指定名称的枚举值
          Season spring = Enum.valueOf(Season.class, "SPRING");
          System.out.println(spring);
          System.out.println(Season.SPRING == spring);
  //        values()       获得所有的枚举项
          Season[] values = Season.values();
          for (Season value : values) {
              System.out.println(value);
          }
      }
  }

11-9 注解

25-注解-注解的优势

代码更加简洁,方便

26-注解-注解的概述

对程序进行标注和解释

  • 注解和注释的区别
    • 注释: 给程序员看的
    • 注解: 给编译器看的

27-注解-自定义注解

 public @interface 注解名称 { 
     public 属性类型 属性名() default 默认值 ; 
 } 

属性类型

  • 基本数据类型
  • String
  • Class
  • 注解
  • 枚举
  • 以上类型的一维数组
  public @interface Anno2 {
  }

  public enum Season {
      SPRING,SUMMER,AUTUMN,WINTER;
  }


  public @interface Anno1 {
      //定义一个基本类型的属性
      int a () default 23;

      //定义一个String类型的属性

      public String name() default "itheima";

      //定义一个Class类型的属性

      public Class clazz() default Anno2.class;

      //定义一个注解类型的属性

      public Anno2 anno() default @Anno2;

      //定义一个枚举类型的属性

      public Season season() default Season.SPRING;

      //以上类型的一维数组

      //int数组

      public int[] arr() default {1,2,3,4,5};

      //枚举数组

      public Season[] seasons() default {Season.SPRING,Season.SUMMER};

      //value。后期我们在使用注解的时候,如果我们只需要给注解的value属性赋值。

      //那么value就可以省略

      public String value();

  }

  //在使用注解的时候如果注解里面的属性没有指定默认值。
  //那么我们就需要手动给出注解属性的设置值。
  //@Anno1(name = "itheima")
  @Anno1("abc")
  public class AnnoDemo {
  }

28-注解-特殊属性value

如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可

29-注解-自定义注解练习

30-注解-元注解

元注解就是描述注解的注解

  @Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})  //指定注解使用的位置(成员变量,类,方法)

  @Retention(RetentionPolicy.RUNTIME) //指定该注解的存活时间

  //@Inherited //指定该注解可以被继承

  public @interface Anno {
  }


  @Anno
  public class Person {
  }

  public class Student extends Person {
      public void show(){
          System.out.println("student.......show..........");
      }
  }

  public class StudentDemo {
      public static void main(String[] args) throws ClassNotFoundException {
          //获取到Student类的字节码文件对象
          Class clazz = Class.forName("com.itheima.myanno4.Student");
          //获取注解。
          boolean result = clazz.isAnnotationPresent(Anno.class);
          System.out.println(result);
      }
  }

11-11 单元测试

08-单元测试-概述

JUnit是一个 Java 编程语言的单元测试工具。JUnit 是一个非常重要的测试工具

  • JUnit是一个开放源代码的测试工具。
  • 提供注解来识别测试方法。
  • JUnit测试可以让你编写代码更快,并能提高质量。
  • JUnit优雅简洁。没那么复杂,花费时间较少。
  • JUnit在一个条中显示进度。如果运行良好则是绿色;如果运行失败,则变成红色。

09-单元测试-基本使用

  1. 将junit的jar包导入到工程中 junit-4.9.jar

  2. 编写测试方法该测试方法必须是公共的无参数无返回值的非静态方法

  3. 在测试方法上使用@Test注解标注该方法是一个测试方法

  4. 选中测试方法右键通过junit运行该方法

  public class JunitDemo1 {
      @Test
      public void add() {
          System.out.println(2 / 0);
          int a = 10;
          int b = 20;
          int sum = a + b;
          System.out.println(sum);
      }
  }

10-单元测试-三个常用注解before,test,after

注解含义
@Test表示测试该方法
@Before在测试的方法前运行
@After在测试的方法后运行
public class JunitDemo2 {
    @Before
    public void before() {
              // 在执行测试代码之前执行,一般用于初始化操作
        System.out.println("before");
    }
    @Test
    public void test() {
              // 要执行的测试代码
        System.out.println("test");
    }

    @After
    public void after() {
          // 在执行测试代码之后执行,一般用于释放资源
        System.out.println("after");
    }
}

11-12 日志技术

11-日志技术-日志技术与输出语句的区别

  • 概述

程序中的日志可以用来记录程序在运行的时候点点滴滴。并可以进行永久存储。

  • 日志与输出语句的区别
输出语句日志技术
取消日志需要修改代码,灵活性比较差不需要修改代码,灵活性比较好
输出位置只能是控制台可以将日志信息写入到文件或者数据库中
多线程和业务代码处于一个线程中多线程方式记录日志,不影响业务代码的性能

12-日志技术-体系结构和Log4J

体系结构

  • Log4J

Log4j是Apache的一个开源项目。

通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件等位置。

我们也可以控制每一条日志的输出格式。

通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

13-日志技术-Log4J入门案例

  • 使用步骤
  1. 导入log4j的相关jar包
  2. 编写log4j配置文件
  3. 在代码中获取日志的对象
  4. 按照级别设置记录日志信息
// log4j的配置文件,名字为log4j.properties, 放在src根目录下

log4j.rootLogger=debug,my,fileAppender



### direct log messages to my ###

log4j.appender.my=org.apache.log4j.ConsoleAppender

log4j.appender.my.ImmediateFlush = true

log4j.appender.my.Target=System.out

log4j.appender.my.layout=org.apache.log4j.PatternLayout

log4j.appender.my.layout.ConversionPattern=%d %t %5p %c{1}:%L - %m%n



# fileAppenderʾ

log4j.appender.fileAppender=org.apache.log4j.FileAppender

log4j.appender.fileAppender.ImmediateFlush = true

log4j.appender.fileAppender.Append=true

log4j.appender.fileAppender.File=D:/log4j-log.log

log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout

log4j.appender.fileAppender.layout.ConversionPattern=%d %5p %c{1}:%L - %m%n



// 测试类

public class Log4JTest01 {

    //使用log4j的api来获取日志的对象
    //弊端:如果以后我们更换日志的实现类,那么下面的代码就需要跟着改
    //不推荐使用
    //private static final Logger LOGGER = Logger.getLogger(Log4JTest01.class);

    //使用slf4j里面的api来获取日志的对象
    //好处:如果以后我们更换日志的实现类,那么下面的代码不需要跟着修改
    //推荐使用

    private static  final Logger LOGGER = LoggerFactory.getLogger(Log4JTest01.class);

    public static void main(String[] args) {

        //1.导入jar包
        //2.编写配置文件
        //3.在代码中获取日志的对象
        //4.按照日志级别设置日志信息
        
        LOGGER.debug("debug级别的日志");

        LOGGER.info("info级别的日志");

        LOGGER.warn("warn级别的日志");

        LOGGER.error("error级别的日志");

    }

}

14-日志技术-Log4J三个核心

三个核心

  • Loggers(记录器) 日志的级别

    • Loggers组件在此系统中常见的五个级别:DEBUG、INFO、WARN、ERROR 和 FATAL。
    • DEBUG < INFO < WARN < ERROR < FATAL。
    • Log4j有一个规则:只输出级别不低于设定级别的日志信息。
  • Appenders(输出源) 日志要输出的地方

把日志输出到不同的地方,如控制台(Console)、文件(Files)等。

  • org.apache.log4j.ConsoleAppender(控制台)
  • org.apache.log4j.FileAppender(文件)
  • Layouts(布局) 日志输出的格式

可以根据自己的喜好规定日志输出的格式

常用的布局管理器:

org.apache.log4j.PatternLayout(可以灵活地指定布局模式)

org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)

org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)

15-日志技术-配置文件详解

配置根Logger

  • 格式

    • log4j.rootLogger=日志级别,appenderName1,appenderName2,…
  • 日志级别

    • OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别。
  • appenderName1

    • 就是指定日志信息要输出到哪里。可以同时指定多个输出目的地,用逗号隔开。
    • 例如:log4j.rootLogger=INFO,ca,fa
  • ConsoleAppender常用的选项
    • ImmediateFlush=true
      • 表示所有消息都会被立即输出,设为false则不输出,默认值是true。
  • Target=System.err
    • 默认值是System.out。
  • FileAppender常用的选项
    • ImmediateFlush=true
      • 表示所有消息都会被立即输出。设为false则不输出,默认值是true
  • Append=false
    • true表示将消息添加到指定文件中,原来的消息不覆盖。
    • false则将消息覆盖指定的文件内容,默认值是true。
  • File=D:/logs/logging.log4j
    • 指定消息输出到logging.log4j文件中
  • PatternLayout常用的选项
    • ConversionPattern=%m%n
      • 设定以怎样的格式显示消息

16-日志技术-Log4j在项目中的应用

步骤

  1. 导入相关的依赖
  2. 将资料中的properties配置文件复制到src目录下
  3. 在代码中获取日志的对象
  4. 按照级别设置记录日志信息

代码实现

@WebServlet(urlPatterns = "/servlet/loginservlet")

public class LoginServlet implements HttpServlet{

    //获取日志的对象

    private static final Logger LOGGER = LoggerFactory.getLogger(LoginServlet.class);

    @Override
    public void service(HttpRequest httpRequest, HttpResponse httpResponse) {

       //处理

        System.out.println("LoginServlet处理了登录请求");

        LOGGER.info("现在已经处理了登录请求,准备给浏览器响应");

       //响应

        httpResponse.setContentTpye("text/html;charset=UTF-8");

        httpResponse.write("登录成功");

    }

}