5/27/2014
2:16:00 PM 0

Apache Commons Logging 整合 java.util.logging

  1. 設定 commons logging 使用 java.util.logging

    在應用程式的 classpath 中加入 commons-logging.properties 檔案
    commons-logging.properties 內容如下,作用是要 commons.logging 使用 Jdk14Logger
    org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
    
    若不使用 commons-logging.properties, commons logging 會先搜尋 classpath 中是否存在 log4J , 若存在 log4J 則優先使用 log4J, 若不存 log4J 才會使用 java.util.logging, 順序可參考 org.apache.commons.logging.LogSource

  2. 建立 java.util.logging 設定檔

    建立設定檔 logging.properties, 檔名可自訂
    handlers= java.util.logging.FileHandler
    .level= INFO
    java.util.logging.FileHandler.pattern = test_%g.log
    java.util.logging.FileHandler.encoding = UTF-8
    java.util.logging.FileHandler.limit = 10000000
    java.util.logging.FileHandler.count = 10
    java.util.logging.FileHandler.append = true
    java.util.logging.SimpleFormatter.format = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n
    java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
    
  3. 設定 java.util.logging 讀取設定檔
    方法一
    InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream("logging.properties");
    
    try {
        LogManager.getLogManager().readConfiguration(input);
    } 
    catch (SecurityException | IOException e) {
        e.printStackTrace();
    }
    
    方法二
    設定 system property, 或在啟動程式時加入參數
    example: java -Djava.util.logging.config.file=logging.properties
    
    在不指定設定檔的狀況下, 預設會讀取 System.getProperty("java.home")/lib/logging.properties 檔案, 可參考 LogManager 文件
使用範例
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class TestLog {

    private static final Log log = LogFactory.getLog(TestLog.class);
 
    public static void main(String[] args) {
        log.debug("Debug Message");
        log.info("Info Message");
        log.warn("Warn Message");
        log.error("Error Message");
        log.fatal("Fatal Message");
     }
}
Log LEVEL 定義比較表

Java Logging Commons Logging
SEVERE FATAL
SEVERE ERROR
WARNING WARN
INFO INFO
CONFIG
FINE DEBUG
FINER
FINEST TRACE
5/22/2014
3:19:00 PM 0

Java Type Erasure

Java 的泛型其實是在編譯器上做了手腳,Java 在編譯時期由編譯器幫我們做了型別轉換的檢查,當 compile 成 bytecode 後,我們使用工具觀察,可以發現我們在程式中所使用的泛型全都不見了,也因此程式在 run time 時是看不到泛型的影子,這種泛型的實現方式稱作 type erasure, 其優點是確保了相容性, 而 .NET 的泛型就不一樣了, .NET 的泛型是真正運行於 CLR 層上的功能, 也因此 Java 的泛型與 .NET 相比, Java 多了許多限制

舉個例子,假設我們要實做一個 List, 當索引值超出 List 長度時, 回傳傳入泛型型別的實例

C#
public class Animal
{
    public override String ToString()
    {
        return this.GetType().Name;
    }
}

public class Cat : Animal {}
public class Dog : Animal {}
public class Monkey : Animal {}

public class AnimalList<T> : List<T> where T : Animal
{
    public new T this[int index] 
    { 
        get
        {
            if (index < this.Count)
            {
                return base[index];
            }
            else
            {
                return Activator.CreateInstance<T>();
            }
        }

        set
        {
            base[index] = value;               
        }
    }
}

public static void Main(string[] args)
{
    AnimalList<Animal> a = new AnimalList<Animal>()
    {
        new Cat(),
        new Dog(),
        new Monkey()
    };

    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(a[i]);
    }
}
C# 可利用傳入的 T 型別, 利用 reflection 建立物件實例

Java
public class Animal 
{
    @Override
    public String toString()
    {
        return this.getClass().getSimpleName();
    }
}

public class Cat extends Animal {}
public class Dog extends Animal {}
public class Monkey extends Animal {}

public class AnimalList<T extends Animal> extends ArrayList<T> 
{
    private final Class<T> clazz;

    public AnimalList(Class<T> clazz) 
    {
        this.clazz = clazz;
    }

    @Override
    public T get(int index) 
    {
        T result = null;
     
        if (index < size())
        {
            result = super.get(index);
        }
        else
        {
            try 
            {
                result = this.clazz.newInstance();
            }
            catch (InstantiationException | IllegalAccessException e) 
            {
                e.printStackTrace();
            }
        }
        return result;
    }
}

public static void main(String[] args) 
{
    final AnimalList<Animal> a = new AnimalList<Animal>(Animal.class)
    {{
        add(new Cat());
        add(new Dog());
        add(new Monkey());
    }};

    for (int i = 0; i < 10; i++)
    {
        System.out.println(a.get(i));
    }
}

因 type erasure 的原因, 造成 JVM 在執行時期, 無法利用傳入的 T 型別, 建立物件實例, 所以必須在 constructor 傳入 Class 參數, 利用 Class 建立實例

參考 : http://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#createObjects