避免每个类中都初始化日志类

写代码的时候,很多类里需要打日志,一般写法都是:

Logger log =  LoggerFactory.getLogger(XXX.class); // 或者参数给的是类名字符串

每个类里面都要写,好烦,能否封装一下,自动获取使用日志的类名,这样就不用每个类里都写了:

一个百试不爽的实现方式(通过异常栈获取):

public static Logger getLogger() {

	Logger logger = Logger.getLogger(getInvokingClassName());
	PropertyConfigurator.configure(getConfigFileName());

	return logger;
}
public static String getInvokingClassName()
{
	return new Throwable().getStackTrace()[2].getClassName();
}

有人说这样的方式性能会有问题,网上有人给出了如下几种方式取得类名:

 // 1、通过SecurityManager的保护方法getClassContext()  
    String clazzName = new SecurityManager() {  
        public String getClassName() {  
            return getClassContext()[1].getName();  
        }  
    }.getClassName();  
    System.out.println(clazzName); 
    
  ****以上这个总觉得哪里有限制*****
  
  2、通过分析匿名类名称()  
    String clazzName3 = new Object() {  
        public String getClassName() {  
            String clazzName = this.getClass().getName();  
            return clazzName.substring(0, clazzName.lastIndexOf(‘$‘));  
        }  
    }.getClassName();  
    System.out.println(clazzName3);
    
  3、通过Thread的方法getStackTrace()  
  
    String clazzName4 = Thread.currentThread().getStackTrace()[2].getClassName();  
    System.out.println(clazzName4);
    
    
    注意:虽然以上3中方式都可以拿到类名,但是,写日志的时候,我们是要从日志里看出
    日志是出自那个类,而以上3中都只能显示其自身所在的类信息,却得不到正在写日志的
    类的信息。

其实,文首给出的实现也是jdk里的实现方式:

后面给出的代码是JDK1.4的源代码,和Log4J的源代码。说明其实现原理。
获得调用类,和方法名,就是需要获得当前运行栈的结构。
new Throwable().getStackTrace() 会返回当前运行栈的结构层次。
利用这种原理,可以获得整个运行栈的调用关系。

JDK1.4的java.util.logging包, 通过Throwable.getStackTrace()方法实现的。
// Get the stack trace.
StackTraceElement stack[] = (new Throwable()).getStackTrace();

log4j的实现也是异曲同工:

org.apache.log4j.spi.LocationInfo类。
先用Throwable.printStackTrace()方法把Exception信息打印到一个字符串里。
然后按行分析这个字符串。抽出调用类和方法。

JDK1.5在Thread类里面引入了getStackTrace()和getAllStackTraces()两个方法。这下子,我们不用 (new Throwable()).getStackTrace ();可以调用

Thread.getCurrentThread().getStackTrace()来获得当前线程的运行栈信息。不仅如此,只要权限允许,还可以获得其它线程的运行栈信息。不幸的是,虽然可以拿到栈信息,但是日志打印的时候依然显示的是Thread.getCurrentThread().getStackTrace()该语句所在的类的信息。

时间: 2024-11-06 11:32:33

避免每个类中都初始化日志类的相关文章

【C++】派生类对象初始化基类的引用

//派生类对象初始化基类的引用 //引用是别名,但这个别名只能包含派生类对象中的由基类继承来的隐藏对象 #include <iostream> using namespace std; class B { public: B() { cout<<"B"<<endl; } void fun() { cout<<"B::fun()"<<endl; } private: int x; }; class D : p

包括继承的类的初始化及类的加载一(附源码)

前言 在许多传统语言中,程序是作为启动过程的一部分立刻被加载的.然后是初始化,紧接着程序开始运行.这些语言的初始化过程必须小心控制,以确保定义为static的东西,其初始化顺序不会造成麻烦.例如C++中,如果某个static期望另一个static在被初始化之前就能有效地使用它,那么就会出现问题. Java就不会出现这个问题,因为它采用了一种不同的加载方式.加载是众多变得更加容易的动作之一,因为Java中所有的事物都是对象.请记住,每个类的编译代码都存在于它们自己的独立的文件中.该文件只在需要程序

包括继承的类的初始化及类的加载二(附源码)

前言 在许多传统语言中,程序是作为启动过程的一部分立刻被加载的.然后是初始化,紧接着程序开始运行.这些语言的初始化过程必须小心控制,以确保定义为static的东西,其初始化顺序不会造成麻烦.例如C++中,如果某个static期望另一个static在被初始化之前就能有效地使用它,那么就会出现问题. Java就不会出现这个问题,因为它采用了一种不同的加载方式.加载是众多变得更加容易的动作之一,因为Java中所有的事物都是对象.请记住,每个类的编译代码都存在于它们自己的独立的文件中.该文件只在需要程序

苹果新的编程语言 Swift 语言进阶(十一)--实例的初始化与类的析构

一 .实例的初始化          实例的初始化是准备一个类.结构或枚举的实例以便使用的过程.初始化包括设置一个实例的每一个存储属性为一个初始值,以及执行任何其它新的实例能够使用之前需要的设置或初始化. 一个类.结构或枚举能定义一个初始化方法来设置它的特性,用来确保它的实例的所有属性都有有效的初始值. 通过调用类.结构或枚举提供的初始化方法来执行实例的初始化过程. 类的实例也能实现一个析构,用来在类的实例释放之前执行任何特定的清除过程来释放分配的专有资源. 1 . 初始化方法的定义 初始化方法

类的生命周期(下)类的初始化【转】

上接深入java虚拟机——深入java虚拟机(二)——类加载器详解(上),在上一篇文章中,我们讲解了类的生命周期的加载和连接,这一篇我们接着上面往下看. 类的初始化:在类的生命周期执行完加载和连接之后就开始了类的初始化.在类的初始化阶段,java虚拟机执行类的初始化语句,为类的静态变量赋值,在程序中,类的初始化有两种途径:(1)在变量的声明处赋值.(2)在静态代码块处赋值,比如下面的代码,a就是第一种初始化,b就是第二种初始化 [html] view plaincopyprint? public

java类的初始化和对象的创建顺序

学习java编程思想--类的初始化p146 类的加载顺序* 1加载器启动找到 xxx.class文件,通过extends关键字寻找基类,先加载基类* 2类初始化先初始化static成员变量和static--->* 2先初始化父类的static成员变量和static* 3再初始化本类的static成员变量和static * 类加载之后,对象创建开始* 1先加载父类的非静态成员变量(静态成员变量在类初始化的时候已经加载,非静态成员变量要随对象的创建而初始化)* 2先加载父类的构造函数* 3再加载本类

关于“只有静态常量整型数据成员才可以在类中初始化”

关于“只有静态常量整型数据成员才可以在类中初始化” 关于类中的静态成员变量, 在类中只能声明,不能定义注意在类的内部只是声明,不是定义 类中的静态变量是属于类的,不属于某个对象!不能在定义对象时对变量初始化!就时不能用构造函数来初始化!而且使用时应加上类名,而不是对象.例如: class A{ static int x; static int y; } int A::x=1; int A::y=2;//这样初始化! int main(){ cout<<A::x<<endl; cou

深入java虚拟机(三)——类的生命周期(下)类的初始化

上接深入java虚拟机——深入java虚拟机(二)——类加载器详解(上),在上一篇文章中,我们讲解了类的生命周期的加载和连接,这一篇我们接着上面往下看. 类的初始化:在类的生命周期执行完加载和连接之后就开始了类的初始化.在类的初始化阶段,java虚拟机执行类的初始化语句,为类的静态变量赋值,在程序中,类的初始化有两种途径:(1)在变量的声明处赋值.(2)在静态代码块处赋值,比如下面的代码,a就是第一种初始化,b就是第二种初始化 [html] view plaincopyprint? public

【深入理解Java虚拟机】类的初始化过程

类的初始化过程 类的加载过程.png 加载 将 Class 文件以二进制的形式加载到内存中 验证 校验 Class 文件是否安全,是否被正确的修改等 准备 为类变量申请内存,设置默认值,(初始化变量的默认值,比如int初始化为0,reference初始化为null) 但是达到类的初始化之前都没有初始化为真正的值. 零值.png 解析 将符号引用转换为直接引用 初始化 搜集并执行static代码块,以及 方法的执行, 是静态变量以及static 代码块组成 使用 为新对象申请内存, 为示例变量初始