详解Strut2中ActionSupport类的日志处理功能

来源:互联网 发布:php mvp 编辑:程序博客网 时间:2024/04/29 03:12

要点:

1.strut2是依赖于xwork这个包,这一点也struts1与struts2的区别之一。     

2.在strut2中ActionSupport类的Logger对象LOG,它是一个静态对象,通过日志工厂LoggerFactory去获取的。在采用STRUTS2进行开发时,可以让action类继承ActionSupport,即可使用Logger进行日志处理(Logger,包含trace debug info warn error fatal等六个层别的打印)


下面通过Logger对象,了解一下Struts2的日志处理过程

ActionSupport持有LOG对象,源码如下:

public class ActionSupport
  implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable
{
  protected static Logger LOG = LoggerFactory.getLogger(ActionSupport.class);

......

那么LoggerFactory方法,getLogger是如何实现的呢?

##########################XWORK包下##########################

首先,LoggerFactory是一个抽象类,它持有一把读写锁lock(ReadWriteLock),以及一个日志工厂factory(LoggerFactory).

 private static final ReadWriteLock lock = new ReentrantReadWriteLock();
  private static LoggerFactory factory;

提供两个静态方式,获取Logger对象,一种是通过Class<?> cls,一种是通过类名 字符串参数,如Hello.class就用“Hello”,

  public static Logger getLogger(Class<?> cls)
  {
    return getLoggerFactory().getLoggerImpl(cls);
  }

  public static Logger getLogger(String name) {
    return getLoggerFactory().getLoggerImpl(name);
  }
从上面看,实现上是调用其自身的实现方法getLoggerImpl,它自身的getLoggerImpl方法如下,都是抽象方法(为什么?往下看方法getLoggerFactory,就知道了)

 protected abstract Logger getLoggerImpl(Class<?> paramClass);

  protected abstract Logger getLoggerImpl(String paramString);

#################getLoggerFactory();的实现#####################

在理解getLoggerFactory().getLoggerImpl(cls);这个语句之前,我们先理解一下getLoggerFactory();的实现

protected static LoggerFactory getLoggerFactory() {
    lock.readLock().lock(); //锁定 读锁
    try {
      if (factory != null) {  //工厂是共用的,如果不用空,返回该工厂对象
        LoggerFactory localLoggerFactory = factory;
        return localLoggerFactory;  //如果不用空,返回该工厂对象
      } } finally { lock.readLock().unlock();//解除  读锁
    }
    lock.writeLock().lock();  //锁定  写锁;前提,如果当前factory为空,需要创建新的工厂,使用ActionSupport 里边的LoggerFactory.getLogger()方法,展开即getLoggerFactory();方法返回值 不为空
    try {
      if (factory == null) {  //important!!!!!!  通过 反射 reflection 获取commons-logging下的LogFactory对象
        try {
          Class.forName("org.apache.commons.logging.LogFactory");//为什么呢?
          factory = new CommonsLoggerFactory();//在写锁当环境中 创建 CommonsLoggerFactory对象,要用到LogFactory对象 ,详细代码,往下看!
        }
        catch (java.lang.ClassNotFoundException ex) {
          factory = new JdkLoggerFactory();
        }
      }
      ex = factory;
      return ex; } finally { lock.writeLock().unlock(); } throw localObject2;//解除  写锁
  }

注:CommonsLoggerFactory 其实是LoggerFactory的子类,只是它是一个非抽象对象,实现了LoggerFactory的下面的两个实现方法:

 protected abstract Logger getLoggerImpl(Class<?> paramClass);

  protected abstract Logger getLoggerImpl(String paramString);


################创建  CommonsLoggerFactory  对象 的实现################


public class CommonsLoggerFactory extends LoggerFactory
{
  protected Logger getLoggerImpl(Class<?> cls)
  {
    return new CommonsLogger(LogFactory.getLog(cls));
  }

  protected Logger getLoggerImpl(String name)
  {
    return new CommonsLogger(LogFactory.getLog(name));
  }
}

#######COMMONS-LOGGIN包下的###


######################  LogFactory对象getLog方法 ,参数为Class cls 的实现################

  public static Log getLog(Class clazz)
    throws LogConfigurationException
  {
    return getFactory().getInstance(clazz);
  }


在看下commons-logging下的LogFactory类的getFactory()方法的实现之前,

先理解一下LogFactory的静态加载块:

  static
  {
    thisClassLoader = getClassLoader(LogFactory.class);  //获取当前类(LogFactory)的类加载器
    initDiagnostics();
    logClassLoaderEnvironment(LogFactory.class);
    factories = createFactoryStore();
    if (isDiagnosticsEnabled())
      logDiagnostic("BOOTSTRAP COMPLETED");
  }

#################initDiagnostics####################

  private static void initDiagnostics()
  {
    try
    {
      String dest = getSystemProperty("org.apache.commons.logging.diagnostics.dest", null);  //读取项目根目录下的commons-loggings.properties文件里边的

//org.apache.commons.logging.diagnostics.dest系统变量

      if (dest == null) {
        return;
      }
    }
    catch (SecurityException ex)
    {
      return;
    }
    String dest;
    if (dest.equals("STDOUT"))
      diagnosticsStream = System.out;
    else if (dest.equals("STDERR"))
      diagnosticsStream = System.err;
    else {//其他情况、根据文件名创建打印流diagnosticsStream(PrintStream)
      try
      {
        FileOutputStream fos = new FileOutputStream(dest, true);
        diagnosticsStream = new PrintStream(fos);
      }
      catch (IOException ex) {
        return;
      }

    }

    String classLoaderName;//初始化classLoaderName类加载器名称
    try
    {
      ClassLoader classLoader = thisClassLoader;
      String classLoaderName;
      if (thisClassLoader == null)
        classLoaderName = "BOOTLOADER";
      else
        classLoaderName = objectId(classLoader);//objectId返回形式为“该类的完整路径(如java.lang.String)+@+该类在内存中的hashcode编码”
    }
    catch (SecurityException e)
    {
      String classLoaderName;
      classLoaderName = "UNKNOWN";
    }
    diagnosticPrefix = "[LogFactory from " + classLoaderName + "] ";//定义诊断前缀字符串
  }
#################logClassLoaderEnvironment#######

###################这个类比较简单 ,只是加载类加载器,并打印一些信息####################

##################前提是isDiagnosticsEnabled()为true,即diagnosticsStream(PrintStream) 对象不为空的情况#############
  private static void logClassLoaderEnvironment(Class clazz)
  {
    if (!isDiagnosticsEnabled()) {
      return;
    }

    try
    {
      logDiagnostic("[ENV] Extension directories (java.ext.dir): " + System.getProperty("java.ext.dir"));
      logDiagnostic("[ENV] Application classpath (java.class.path): " + System.getProperty("java.class.path"));
    } catch (SecurityException ex) {
      logDiagnostic("[ENV] Security setting prevent interrogation of system classpaths.");
    }

    String className = clazz.getName();
    try
    {
      classLoader = getClassLoader(clazz);
    }
    catch (SecurityException ex)
    {
      ClassLoader classLoader;
      logDiagnostic("[ENV] Security forbids determining the classloader for " + className);

      return;
    }
    ClassLoader classLoader;
    logDiagnostic("[ENV] Class " + className + " was loaded via classloader " + objectId(classLoader));

    logHierarchy("[ENV] Ancestry of classloader which loaded " + className + " is ", classLoader);
  }


#################createFactoryStore####################

 private static final Hashtable createFactoryStore() { //这里返回一个线程安全,支持同步的hashtable对象,用于保存工厂集合

    Hashtable result = null;
    String storeImplementationClass;
    try {

storeImplementationClass = getSystemProperty("org.apache.commons.logging.LogFactory.HashtableImpl", null);//读取系统配置,在commons-loggin.properties下配置
    }
    catch (SecurityException ex)
    {
      String storeImplementationClass;
      storeImplementationClass = null;
    }

    if (storeImplementationClass == null)//如果没有配置,读出默认弱hashtable对象
      storeImplementationClass = "org.apache.commons.logging.impl.WeakHashtable";
    try
    {
      Class implementationClass = Class.forName(storeImplementationClass);//反射获取该实例返回
      result = (Hashtable)implementationClass.newInstance();
    }
    catch (Throwable t)
    {
      if (!"org.apache.commons.logging.impl.WeakHashtable".equals(storeImplementationClass))
      {
        if (isDiagnosticsEnabled())
        {
          logDiagnostic("[ERROR] LogFactory: Load of custom hashtable failed");
        }
        else
        {
          System.err.println("[ERROR] LogFactory: Load of custom hashtable failed");
        }
      }
    }
    if (result == null) {
      result = new Hashtable();
    }
    return result;
  }

#####################现在静态块代码已经分析完了,只是一个静态加载,比较简单###接下继续前面的Log#################

###############LogFactory类的getFactory()方法的实现##################################

  首先调用getContextClassLoaderInternal()方法,通过AccessController对象调用directGetContextClassLoader

#################directGetContextClassLoader 的代码如下##########反射####################################

Method method = Thread.class.getMethod("getContextClassLoader", (Class[])null);
classLoader = (ClassLoader)method.invoke(Thread.currentThread(), (Object[])null);

#########################如果classLoader为空,则返回当前类的加载器########

classLoader = getClassLoader(LogFactory.class);

  接下来,通过classLoader类加载器作为参数,获取缓存工厂

factory  = getCachedFactory(classLoader)