一、概述
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来行代码,包含的知识点,有单例模式、语法糖--枚举。
网友评论