美文网首页
log4j2-core的源码学习(一)

log4j2-core的源码学习(一)

作者: 天草二十六_简村人 | 来源:发表于2019-09-26 10:10 被阅读0次

一、概述
log4j2作为一个高性能的日志组件,里面有许多值得学习借鉴的地方。本文是抛砖引玉,先对某一个类的写法进行分析。

二、EventRoute枚举类

package org.apache.logging.log4j.core.async;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AsyncAppender;
import org.apache.logging.log4j.message.Message;

public enum EventRoute {
    ENQUEUE {
        public void logMessage(AsyncLogger asyncLogger, String fqcn, Level level, Marker marker, Message message, Throwable thrown) {
        }

        public void logMessage(AsyncLoggerConfig asyncLoggerConfig, LogEvent event) {
            asyncLoggerConfig.callAppendersInBackgroundThread(event);
        }

        public void logMessage(AsyncAppender asyncAppender, LogEvent logEvent) {
            asyncAppender.logMessageInBackgroundThread(logEvent);
        }
    },
    SYNCHRONOUS {
        public void logMessage(AsyncLogger asyncLogger, String fqcn, Level level, Marker marker, Message message, Throwable thrown) {
        }

        public void logMessage(AsyncLoggerConfig asyncLoggerConfig, LogEvent event) {
            asyncLoggerConfig.callAppendersInCurrentThread(event);
        }

        public void logMessage(AsyncAppender asyncAppender, LogEvent logEvent) {
            asyncAppender.logMessageInCurrentThread(logEvent);
        }
    },
    DISCARD {
        public void logMessage(AsyncLogger asyncLogger, String fqcn, Level level, Marker marker, Message message, Throwable thrown) {
        }

        public void logMessage(AsyncLoggerConfig asyncLoggerConfig, LogEvent event) {
        }

        public void logMessage(AsyncAppender asyncAppender, LogEvent coreEvent) {
        }
    };

    private EventRoute() {
    }

    public abstract void logMessage(AsyncLogger var1, String var2, Level var3, Marker var4, Message var5, Throwable var6);

    public abstract void logMessage(AsyncLoggerConfig var1, LogEvent var2);

    public abstract void logMessage(AsyncAppender var1, LogEvent var2);
}

1、第一,枚举定义了一个私有构造方法,意味着不对外new。
2、第二,声明了三个抽象方法,枚举作为一个语法糖,有必要针对上面的枚举类,查看它的字节码。详细见下文。
3、第三,定义了三个成员变量,内部实现不一样。
4、总结,其实这里就是通过枚举做到了单例的设计模式。

三、EventRoute枚举类的字节码

// class version 51.0 (51)
// access flags 0x4421
// signature Ljava/lang/Enum<Lorg/apache/logging/log4j/core/async/EventRoute;>;
// declaration: org/apache/logging/log4j/core/async/EventRoute extends java.lang.Enum<org.apache.logging.log4j.core.async.EventRoute>
public abstract enum org/apache/logging/log4j/core/async/EventRoute extends java/lang/Enum  {

  // compiled from: EventRoute.java
  // access flags 0x4008
  static enum INNERCLASS org/apache/logging/log4j/core/async/EventRoute$3 null null
  // access flags 0x4008
  static enum INNERCLASS org/apache/logging/log4j/core/async/EventRoute$2 null null
  // access flags 0x4008
  static enum INNERCLASS org/apache/logging/log4j/core/async/EventRoute$1 null null

  // access flags 0x4019
  public final static enum Lorg/apache/logging/log4j/core/async/EventRoute; ENQUEUE

  // access flags 0x4019
  public final static enum Lorg/apache/logging/log4j/core/async/EventRoute; SYNCHRONOUS

  // access flags 0x4019
  public final static enum Lorg/apache/logging/log4j/core/async/EventRoute; DISCARD

  // access flags 0x101A
  private final static synthetic [Lorg/apache/logging/log4j/core/async/EventRoute; $VALUES

  // access flags 0x9
  public static values()[Lorg/apache/logging/log4j/core/async/EventRoute;
   L0
    LINENUMBER 34 L0
    GETSTATIC org/apache/logging/log4j/core/async/EventRoute.$VALUES : [Lorg/apache/logging/log4j/core/async/EventRoute;
    INVOKEVIRTUAL [Lorg/apache/logging/log4j/core/async/EventRoute;.clone ()Ljava/lang/Object;
    CHECKCAST [Lorg/apache/logging/log4j/core/async/EventRoute;
    ARETURN
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x9
  public static valueOf(Ljava/lang/String;)Lorg/apache/logging/log4j/core/async/EventRoute;
   L0
    LINENUMBER 34 L0
    LDC Lorg/apache/logging/log4j/core/async/EventRoute;.class
    ALOAD 0
    INVOKESTATIC java/lang/Enum.valueOf (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
    CHECKCAST org/apache/logging/log4j/core/async/EventRoute
    ARETURN
   L1
    LOCALVARIABLE name Ljava/lang/String; L0 L1 0
    MAXSTACK = 2
    MAXLOCALS = 1

  // access flags 0x2
  // signature ()V
  // declaration: void <init>()
  private <init>(Ljava/lang/String;I)V
   L0
    LINENUMBER 34 L0
    ALOAD 0
    ALOAD 1
    ILOAD 2
    INVOKESPECIAL java/lang/Enum.<init> (Ljava/lang/String;I)V
    RETURN
   L1
    LOCALVARIABLE this Lorg/apache/logging/log4j/core/async/EventRoute; L0 L1 0
    MAXSTACK = 3
    MAXLOCALS = 3

  // access flags 0x401
  public abstract logMessage(Lorg/apache/logging/log4j/core/async/AsyncLogger;Ljava/lang/String;Lorg/apache/logging/log4j/Level;Lorg/apache/logging/log4j/Marker;Lorg/apache/logging/log4j/message/Message;Ljava/lang/Throwable;)V

  // access flags 0x401
  public abstract logMessage(Lorg/apache/logging/log4j/core/async/AsyncLoggerConfig;Lorg/apache/logging/log4j/core/LogEvent;)V

  // access flags 0x401
  public abstract logMessage(Lorg/apache/logging/log4j/core/appender/AsyncAppender;Lorg/apache/logging/log4j/core/LogEvent;)V

  // access flags 0x1000
  synthetic <init>(Ljava/lang/String;ILorg/apache/logging/log4j/core/async/EventRoute$1;)V
   L0
    LINENUMBER 34 L0
    ALOAD 0
    ALOAD 1
    ILOAD 2
    INVOKESPECIAL org/apache/logging/log4j/core/async/EventRoute.<init> (Ljava/lang/String;I)V
    RETURN
   L1
    LOCALVARIABLE this Lorg/apache/logging/log4j/core/async/EventRoute; L0 L1 0
    LOCALVARIABLE x0 Ljava/lang/String; L0 L1 1
    LOCALVARIABLE x1 I L0 L1 2
    LOCALVARIABLE x2 Lorg/apache/logging/log4j/core/async/EventRoute$1; L0 L1 3
    MAXSTACK = 3
    MAXLOCALS = 4

  // access flags 0x8
  static <clinit>()V
   L0
    LINENUMBER 38 L0
    NEW org/apache/logging/log4j/core/async/EventRoute$1
    DUP
    LDC "ENQUEUE"
    ICONST_0
    INVOKESPECIAL org/apache/logging/log4j/core/async/EventRoute$1.<init> (Ljava/lang/String;I)V
    PUTSTATIC org/apache/logging/log4j/core/async/EventRoute.ENQUEUE : Lorg/apache/logging/log4j/core/async/EventRoute;
   L1
    LINENUMBER 57 L1
    NEW org/apache/logging/log4j/core/async/EventRoute$2
    DUP
    LDC "SYNCHRONOUS"
    ICONST_1
    INVOKESPECIAL org/apache/logging/log4j/core/async/EventRoute$2.<init> (Ljava/lang/String;I)V
    PUTSTATIC org/apache/logging/log4j/core/async/EventRoute.SYNCHRONOUS : Lorg/apache/logging/log4j/core/async/EventRoute;
   L2
    LINENUMBER 76 L2
    NEW org/apache/logging/log4j/core/async/EventRoute$3
    DUP
    LDC "DISCARD"
    ICONST_2
    INVOKESPECIAL org/apache/logging/log4j/core/async/EventRoute$3.<init> (Ljava/lang/String;I)V
    PUTSTATIC org/apache/logging/log4j/core/async/EventRoute.DISCARD : Lorg/apache/logging/log4j/core/async/EventRoute;
   L3
    LINENUMBER 34 L3
    ICONST_3
    ANEWARRAY org/apache/logging/log4j/core/async/EventRoute
    DUP
    ICONST_0
    GETSTATIC org/apache/logging/log4j/core/async/EventRoute.ENQUEUE : Lorg/apache/logging/log4j/core/async/EventRoute;
    AASTORE
    DUP
    ICONST_1
    GETSTATIC org/apache/logging/log4j/core/async/EventRoute.SYNCHRONOUS : Lorg/apache/logging/log4j/core/async/EventRoute;
    AASTORE
    DUP
    ICONST_2
    GETSTATIC org/apache/logging/log4j/core/async/EventRoute.DISCARD : Lorg/apache/logging/log4j/core/async/EventRoute;
    AASTORE
    PUTSTATIC org/apache/logging/log4j/core/async/EventRoute.$VALUES : [Lorg/apache/logging/log4j/core/async/EventRoute;
    RETURN
    MAXSTACK = 4
    MAXLOCALS = 0
}

分析上述的字节码内容,可以得知以下信息:
1、它继承了java.lang.Enum,详细的jdk源码见下文。
2、包含静态方法,values()和valueOf();定义了三个静态不可变的成员变量ENQUEUE、SYNCHRONOUS、DISCARD。
特别是values()方法,在父类Enum.java中也未能找到。

五、java.lang.Enum.java的源码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package java.lang;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
    private final String name;
    private final int ordinal;

    public final String name() {
        return this.name;
    }

    public final int ordinal() {
        return this.ordinal;
    }

    protected Enum(String var1, int var2) {
        this.name = var1;
        this.ordinal = var2;
    }

    public String toString() {
        return this.name;
    }

    public final boolean equals(Object var1) {
        return this == var1;
    }

    public final int hashCode() {
        return super.hashCode();
    }

    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    public final int compareTo(E var1) {
        if (this.getClass() != var1.getClass() && this.getDeclaringClass() != var1.getDeclaringClass()) {
            throw new ClassCastException();
        } else {
            return this.ordinal - var1.ordinal;
        }
    }

    public final Class<E> getDeclaringClass() {
        Class var1 = this.getClass();
        Class var2 = var1.getSuperclass();
        return var2 == Enum.class ? var1 : var2;
    }

    public static <T extends Enum<T>> T valueOf(Class<T> var0, String var1) {
        Enum var2 = (Enum)var0.enumConstantDirectory().get(var1);
        if (var2 != null) {
            return var2;
        } else if (var1 == null) {
            throw new NullPointerException("Name is null");
        } else {
            throw new IllegalArgumentException("No enum constant " + var0.getCanonicalName() + "." + var1);
        }
    }

    protected final void finalize() {
    }

    private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        throw new InvalidObjectException("can't deserialize enum");
    }

    private void readObjectNoData() throws ObjectStreamException {
        throw new InvalidObjectException("can't deserialize enum");
    }
}

1、枚举类最重要的一个点就是它的成员变量和大多数方法,都是有final修饰,为不可变的。
做到了线程安全。
2、它实现了Serializable接口,主动抛异常InvalidObjectException,“can't deserialize enum"。
3、实现了接口Comparable,compareTo()方法实现,当类相同,且都是枚举,比较他们的ordinal大小。
3、valueOf(),实际上还是依靠values()方法,把成员变量放到一个hashmap里。
4、像equals/hashCode/clone/compareTo/都是final方法。
equals方法实现,就是 == 比较。

六、总结
一个小小的类,50来行代码,包含的知识点,有单例模式、语法糖--枚举。

相关文章

网友评论

      本文标题:log4j2-core的源码学习(一)

      本文链接:https://www.haomeiwen.com/subject/pjzwyctx.html