1、一直在看源代码,虽然都能从里面学到很多东西,但时常迷失在源代码的结构中。只能字里行间学到一些实现。
这篇博客主要分析logging结构。
第一个实现:
package MyLogging;
import logging.Log;
import logging.LogFactory;
public class Test2 {
private static Log log = LogFactory.getLog(Test2.class);
public static void main(String[] args) {
log.error("ERROR1");
log.debug("DEBUG2");
log.warn("WARN3");
log.info("INFO4");
log.trace("TRACE5");
System.out.println(log.getClass());
}
}
输出结果:
三月 13, 2015 10:31:17 上午 MyLogging.Test2 main
严重: ERROR1
三月 13, 2015 10:31:17 上午 MyLogging.Test2 main
警告: WARN3
三月 13, 2015 10:31:17 上午 MyLogging.Test2 main
信息: INFO4
class MyLogging.Jdk14Logger
采用不影响输出结果为目的的删除源代码文件。
第一删除 : log 的实现类。 由于我在jdk 中运行程序。可以删除到只剩下LogFactoryImpl.java 和 JDK14Logger.java。
第二删除:LogSource.java 这个是过时的代码。可以删除。
第三删除: logConfigurationException.java 这个是实现runtimeException的
删除之后吧设计到这个异常的都删除。
到这里为止 只剩下Log.java LogFactory.java Jdk14Logger.java 和LogfactoryImplication.java
现在对这几个文件进行进一步删除。
删除原则。如果有 返回,则设置成返回空。 如果没有返回。这删除全部代码,在运行。如果对结果没有影响就删除。。
这样之后:得到了
LogFactory.java
package logging;
public abstract class LogFactory {
public static final String FACTORY_DEFAULT = "MyLogging.LogFactoryImplication";
protected LogFactory() {
}
public abstract Log getInstance(Class clazz);
public static Log getLog(Class clazz) {
LogFactory LogFactory;
try {
LogFactory = (LogFactory) Class.forName(FACTORY_DEFAULT).newInstance();
return LogFactory.getInstance(clazz);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// protected static ClassLoader directGetContextClassLoader() {
// ClassLoader classLoader = null;
// try {
// classLoader = Thread.currentThread().getContextClassLoader();
// } catch (SecurityException ex) {
//
// }
// return classLoader;
// }
}
LogFactoryImpLication.java
package MyLogging;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Hashtable;
import logging.Log;
import logging.LogFactory;
public class LogFactoryImplication extends LogFactory {
public LogFactoryImplication() {
super();
}
private static final String[] classesToDiscover = { "MyLogging.Jdk14Logger" };
private String logClassName;
protected Class logConstructorSignature[] = { java.lang.String.class };
public Log getInstance(Class clazz) {
return getInstance(clazz.getName());
}
public Log getInstance(String name) {
Log instance = newInstance(name);
return instance;
}
protected Log newInstance(String name) {
Object[] params = { name };
Constructor constructor = null;
Class c;
Object o =null;
try {
c = Class.forName(classesToDiscover[0]);
constructor = c.getConstructor(logConstructorSignature);
o = constructor.newInstance(params);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (Log) o;
}
}
从代码中可以看出,程序跳转都是转载方式来实现的。
部分细节介绍:
protected static ClassLoader directGetContextClassLoader() {
ClassLoader classLoader = null;
try {
classLoader = Thread.currentThread().getContextClassLoader();
} catch (SecurityException ex) {
}
return classLoader;
}
这部分主要是获取转载器。不同的编译器可能有不同的ClassLoader
在 Class.Forname(name,ture,CalssLoader);用到:
代码中通过 :
private Log discoverLogImplementation(String logCategory) {
Log result = null;
for (int i = 0; i < classesToDiscover.length && result == null; ++i) {
result = createLogFromClass(classesToDiscover[i], logCategory, true);
}
return result;
}
private Log createLogFromClass(String logAdapterClassName, String logCategory, boolean affectState) {
Object[] params = { logCategory };
Log logAdapter = null;
Constructor constructor = null;
Class logAdapterClass = null;
// ClassLoader currentCL = getBaseClassLoader();
ClassLoader currentCL = null;
for (;;) {
try {
Class c = null;
try {
c = Class.forName(logAdapterClassName);
// c = Class.forName(logAdapterClassName, true, currentCL);
} catch (ClassNotFoundException originalClassNotFoundException) {
}
constructor = c.getConstructor(logConstructorSignature);
Object o = constructor.newInstance(params);
if (o instanceof Log) {
logAdapterClass = c;
logAdapter = (Log) o;
break;
}
} catch (Throwable t) {
break;
}
if (currentCL == null) {
break;
}
currentCL = null;
}
这两个方法来找到相对应的Log实现类。
配置信息找到方法:通过
private static final Properties getConfigurationFile(ClassLoader classLoader, String fileName) {
Properties props = null;
double priority = 0.0;
URL propsUrl = null;
try {
Enumeration urls = getResources(classLoader, fileName);
if (urls == null) {
return null;
}
while (urls.hasMoreElements()) {
URL url = (URL) urls.nextElement();
Properties newProps = getProperties(url);
if (newProps != null) {
if (props == null) {
propsUrl = url;
props = newProps;
String priorityStr = props.getProperty(PRIORITY_KEY);
priority = 0.0;
if (priorityStr != null) {
priority = Double.parseDouble(priorityStr);
}
if (isDiagnosticsEnabled()) {
logDiagnostic("[LOOKUP] Properties file found at '" + url + "'" +
" with priority " + priority);
}
} else {
String newPriorityStr = newProps.getProperty(PRIORITY_KEY);
double newPriority = 0.0;
if (newPriorityStr != null) {
newPriority = Double.parseDouble(newPriorityStr);
}
if (newPriority > priority) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[LOOKUP] Properties file at '" + url + "'" +
" with priority " + newPriority +
" overrides file at '" + propsUrl + "'" +
" with priority " + priority);
}
propsUrl = url;
props = newProps;
priority = newPriority;
} else {
if (isDiagnosticsEnabled()) {
logDiagnostic("[LOOKUP] Properties file at '" + url + "'" +
" with priority " + newPriority +
" does not override file at '" + propsUrl + "'" +
" with priority " + priority);
}
}
}
}
}
} catch (SecurityException e) {
if (isDiagnosticsEnabled()) {
logDiagnostic("SecurityException thrown while trying to find/read config files.");
}
}
if (isDiagnosticsEnabled()) {
if (props == null) {
logDiagnostic("[LOOKUP] No properties file of name '" + fileName + "' found.");
} else {
logDiagnostic("[LOOKUP] Properties file of name '" + fileName + "' found at '" + propsUrl + '"');
}
}
return props;
}
来找到配置信息。。
这里我想到在编写Mapper、reduce时一直不能读取配置文件成功,必须把配置文件上传到HDFS才能成功,可能是因为没有获取ClassLoad。
这个方法是添加缓存的。也就是用HashMap 来存储执行过得Factory
private static void cacheFactory(ClassLoader classLoader, LogFactory factory) {
// Ideally we would assert(factory != null) here. However reporting
// errors from within a logging implementation is a little tricky!
if (factory != null) {
if (classLoader == null) {
nullClassLoaderFactory = factory;
} else {
factories.put(classLoader, factory);
}
}
}
到处差不多都介绍完了。处理过时的LogSource.java 。
Log.java 只是定义几种方式。
然后再去实现它。没有太多价值。唯一的价值就是。不管什么日志。都是调用同一个方法,
protected void log( Level level, String msg, Throwable ex ) {
Logger logger = getLogger();
if (logger.isLoggable(level)) {
// Hack (?) to get the stack trace.
Throwable dummyException = new Throwable();
StackTraceElement locations[] = dummyException.getStackTrace();
// LOGGING-132: use the provided logger name instead of the class name
String cname = name;
String method = "unknown";
// Caller will be the third element
if( locations != null && locations.length > 2 ) {
StackTraceElement caller = locations[2];
method = caller.getMethodName();
}
if( ex == null ) {
logger.logp( level, cname, method, msg );
} else {
logger.logp( level, cname, method, msg, ex );
}
}
}
不怎么会写博客,见谅。