1. 程式人生 > >詳解Strut2中ActionSupport類的日誌處理功能

詳解Strut2中ActionSupport類的日誌處理功能

要點:

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)[email protected]+該類在記憶體中的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)

相關推薦

Strut2ActionSupport日誌處理功能

要點: 1.strut2是依賴於xwork這個包,這一點也struts1與struts2的區別之一。      2.在strut2中ActionSupport類的Logger物件LOG,它是一個靜態物件,通過日誌工廠LoggerFactory去獲取的。在採用STRUTS2

C++與派生的轉換以及虛基

原文來源:https://www.jb51.net/article/72586.htm# C++基類與派生類的轉換 在公用繼承、私有繼承和保護繼承中,只有公用繼承能較好地保留基類的特徵,它保留了除建構函式和解構函式以外的基類所有成員,基類的公用或保護成員的訪問許可權在派生類中全部都按原樣保留下來

pythonformat函式的強大功能

1、引數替換        format函式可以不限定引數個數,不限定引數位置。        一、不設定指定位置,按預設順序           &nb

java的byte

font 資料 結果 可能 詳解 小程序 工作 定義 值範圍 Java也提供了一個byte數據類型,並且是基本類型。java byte是做為最小的數字來處理的,因此它的值域被定義為-128~127,也就是signed byte。下面這篇文章主要給大家介紹了關於java中by

Java的時區TimeZone的用法

void system類 深入 pri comment 相對 系統 就會 lean 一、TimeZone 簡介 TimeZone 表示時區偏移量,也可以計算夏令時。 在操作 Date, Calendar等表示日期/時間的對象時,經常會用到TimeZone;因為不同的時區,

c++的六個預設的成員函式

類的6個預設的成員函式包括: 建構函式、解構函式、拷貝建構函式、賦值運算子過載函式、取地址操作符過載、const 修飾的取地址操作符過載。 這篇文章重點解釋前四個。 (一)建構函式 建構函式,顧名思義

pythonxlrd包的安裝與處理Excel表格

python處理Excel常用到的模組是xlrd。使用xlrd可以非常方便的處理Excel文件,下面這篇文章將給大家詳細介紹python中包xlrd的安裝與利用xlrd處理Excel表格的方法,有需要的朋友們可以參考學習,下面來一起看看吧。 一、安裝xlrd

Python的文字處理

字串 -- 不可改變的序列 如同大多數高階程式語言一樣,變長字串是 Python 中的基本型別。Python 在“後臺”分配記憶體以儲存字串(或其它值),程式設計師不必為此操心。Python 還有一些其它高階語言沒有的字串處理功能。 在 Python 中,字串是“不可改變的序列”。儘管不能“按位置”修改字串

【Oracle】OracleNLS_LANG變量的使用

make fault tro territory font pin onclick 添加 其中 目錄結構: // contents structure [-] 關於NLS_LANG參數 NSL_LANG常用的值 在MS-DOS模式和Batch模式中

RabbitMQ實例+Spring的MQ使用

方法 it is col 一致性 cli 服務器 發送請求 arguments restrict RabbitMQ實例詳解   消息隊列中間件是分布式系統中重要的組件,主要解決應用解耦,異步消息,流量削鋒等問題,實現高性能,高可用,可伸縮和最終一致性架構。 Queue Q

Python的生成器表達式(generator expression)

新元素 括號 tuple 列表推導式 特點 解析式 表達式 但是 bracket      介紹     1、生成器表達式(generator expression)也叫生成器推導式或生成器解析式,用法與列表推導式非常相似,在形式上生成器推導式使用圓括號(parenth

Python的join()函數的用法

pre 說明 bsp 字符 指定 .net 絕對路徑 字典 -s 函數:string.join() Python中有join()和os.path.join()兩個函數,具體作用如下: join(): 連接字符串數組。將字符串、元組、列表中的元素以指定的字符(分

WordPress簡碼格式標簽編寫的基本方法

filter 所有 oot 執行 body 標簽 支持 script tro WordPress 簡碼是一種類似於論壇標簽的東西,格式類似於把尖括號換成中括號的 Html 標簽。簡碼很多人叫做短代碼,但官方的翻譯應該是簡碼,在這裏糾正一下。 簡碼的開發的邏輯比較簡單,主要就

javascript 的比較(==和===)

不一致 mit 如果 asc onu tin 算法 復雜 undefine 抽象相等比較算法 比較運算 x==y, 其中 x 和 y 是值,產生 true 或者 false。這樣的比較按如下方式進行: 若 Type(x) 與 Type(y) 相同, 則 若 Type(x)

舉例Python的split()函數的使用方法

使用方法 imp count say 文章 pri 參考 詳解 參數 這篇文章主要介紹了舉例詳解Python中的split()函數的使用方法,split()函數的使用是Python學習當中的基礎知識,通常用於將字符串切片並轉換為列表,需要的朋友可以參考下 函數:spl

(轉)C#的反射

typeof ref enc sin setvalue abs class 方法測試 strac (轉)http://www.cnblogs.com/Stephenchao/p/4481995.html 反射的用途: (1)使用Assembly定義和加載程序集,加載在

java的數據結構

span 通過 組成 ret hashcode p s 函數 arr 均衡   線性表,鏈表,哈希表是常用的數據結構,在進行Java開發時,JDK已經為我們提供了一系列相應的類來實現基本的數據結構。這些類均在java.util包中。本文試圖通過簡單的描述,向讀者闡述各個類的

webpack的hash、chunkhash、contenthash區別

con tro 們的 tex trac extra lena fig files hash、chunkhash、contenthash hash一般是結合CDN緩存來使用,通過webpack構建之後,生成對應文件名自動帶上對應的MD5值。如果文件內容改變的話,那麽對應文件

js數組foEach和map的用法 jq的$.each和$.map

cnblogs arr 對象 cal for index source asc 原生js 數組中foEach和map的用法詳解 相同點: 1.都是循環遍歷數組(僅僅是數組)中的每一項。 2.forEach() 和 map() 裏面每一次執行匿名函數都支持3個參數:數組中的

(轉)LinuxSSH遠程訪問控制

體系 字符 配置文件 art 文件 優先 class 遠程訪問 安全 詳解Linux中SSH遠程訪問控制 原文:http://blog.51cto.com/dengqi/1260038 SSH:是一種安全通道協議,主要用來實現字符界面的遠程登錄,遠程復制等功能(使用TCP的