Apache Commons-Logging 中的解決方案:
public class LogSource {
// ------------------------------------------------------- Class Attributes
static protected Hashtable logs = new Hashtable();
/** Is log4j available (in the current classpath) */
static protected boolean log4jIsAvailable = false;
/** Is JDK 1.4 logging available */
static protected boolean jdk14IsAvailable = false;
/** Constructor for current log class */
static protected Constructor logImplctor = null;
// ----------------------------------------------------- Class Initializers
static {
// Is Log4J Available?
try {
log4jIsAvailable = null != Class.forName("org.apache.log4j.Logger");
} catch (Throwable t) {
log4jIsAvailable = false;
}
// Is JDK 1.4 Logging Available?
try {
jdk14IsAvailable = null != Class.forName("java.util.logging.Logger") &&
null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger");
} catch (Throwable t) {
jdk14IsAvailable = false;
}
// Set the default Log implementation
String name = null;
try {
name = System.getProperty("org.apache.commons.logging.log");
if (name == null) {
name = System.getProperty("org.apache.commons.logging.Log");
}
} catch (Throwable t) {
}
if (name != null) {
try {
setLogImplementation(name);
} catch (Throwable t) {
try {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
} catch (Throwable u) {
// ignored
}
}
} else {
try {
if (log4jIsAvailable) {
setLogImplementation("org.apache.commons.logging.impl.Log4JLogger");
} else if (jdk14IsAvailable) {
setLogImplementation("org.apache.commons.logging.impl.Jdk14Logger");
} else {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
}
} catch (Throwable t) {
try {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
} catch (Throwable u) {
// ignored
}
}
}
}
//...
}
核心的代碼:
boolean isPresent = null != Class.forName("org.apache.log4j.Logger");
!= 的優先級大於=
所以以上的代碼對應於:
boolean isPresent = (null != Class.forName("org.apache.log4j.Logger"));
SpringMVC 中的解決方案:
public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConverter {
private static final boolean jaxb2Present =
ClassUtils.isPresent("javax.xml.bind.Binder", AllEncompassingFormHttpMessageConverter.class.getClassLoader());
private static final boolean jackson2Present =
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", AllEncompassingFormHttpMessageConverter.class.getClassLoader()) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", AllEncompassingFormHttpMessageConverter.class.getClassLoader());
private static final boolean jackson2XmlPresent =
ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", AllEncompassingFormHttpMessageConverter.class.getClassLoader());
private static final boolean gsonPresent =
ClassUtils.isPresent("com.google.gson.Gson", AllEncompassingFormHttpMessageConverter.class.getClassLoader());
public AllEncompassingFormHttpMessageConverter() {
addPartConverter(new SourceHttpMessageConverter());
if (jaxb2Present && !jackson2XmlPresent) {
addPartConverter(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
addPartConverter(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
addPartConverter(new GsonHttpMessageConverter());
}
if (jackson2XmlPresent) {
addPartConverter(new MappingJackson2XmlHttpMessageConverter());
}
}
}
/**
* Determine whether the Class identified by the supplied name is present and can be loaded.
* 判斷由提供的類名(類的全限定名)標識的類是否存在並可以加載
* 如果類或其中一個依賴關系不存在或無法加載,則返回false
*@param className 要檢查的類的名稱
*@param classLoader 加載該類使用的類加載器
* 可以是 null, 表明使用默認的類加載器
*@return 指定的類是否存在
*/
public static boolean isPresent(String className, ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
}
catch (Throwable ex) {
// Class or one of its dependencies is not present...
return false;
}
}
可見,以上都是用了Class.forName來完成。
Class.forName 在沒有找到該類時拋出ClassNotFoundException 異常。
我們所需要做的僅僅是屏蔽該異常,並設置一個表示當前類不存在的標識。
那么問題來了,我們都知道Class.forName 會導致我們加載的類去執行靜態代碼塊(當然也可以設置不進行初始化),以及靜態屬性的初始化。在JVM中對應於
invokeSpecial 。
但是在java中如何判斷一個類是否存在 這一簡單問題似乎沒有必要這樣做。
那么如下的代碼似乎更符合我們的要求吧?
public static boolean isPresent(String name) {
try {
Thread.currentThread().getContextClassLoader().loadClass(name);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
以上的loadClass(String name) 方法會去調用該類中的protected方法 java.lang.ClassLoader#loadClass(java.lang.String, boolean)
public Class> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
resolve 參數表示是否進行鏈接。