前几天看了一篇文章,名为模块化Java简介 。模块化的思想就是去耦合,这样在升级或者维护的时候都会方便一些,这样的道理大家都知道,但是怎样在实现中完成这一点呢。
作者在“类库也是模块”这一节中介绍了“类库毫无疑问也是模块。对于类库来讲,可能没有一个单一接口与之通信,但往往却有‘public ’ API(可能被用到)和‘private ’ package(文档中说明了其用途)。此外,它们也有自己依赖的类库(比如JMX 或JMS )。这将引起自动依赖管理器引入许多并非必须的类库:以Log4J-1.2.15 为例,引入了超过10个依赖类库(包括javax.mail和javax.jms),尽管这些类库中有不少对于使用Log4J的程序来说根本不需要。 即要做到,某些情况下,一个模块的依赖可以是可选的。”
虽然文章的其他部分看不太懂,但是这个内容倒是可以考察的。Hibernate和iBATIS[注:这里使用的是iBATIS2作为示例]中的日志模块都是与他们的类库模块分开的,那么他们是怎么做到的呢?
Hibernate用的是Apache Commons Logging 开源工具做到的,而iBATIS用的其实就是自己实现的一个简化的Apache Commons Logging:
首先使用定义一个通用的接口,自己在程序中使用的就是这样一个接口:
package com.ibatis.common.logging;
public interface Log {
boolean isDebugEnabled();
void error(String s, Throwable e);
void error(String s);
public void debug(String s);
public void warn(String s);
}
LogFactory 是用来生成这个Log接口实现的工厂类
package com.ibatis.common.logging;
import java.lang.reflect.Constructor;
import com.ibatis.common.resources.Resources;
public class LogFactory {
private static Constructor logConstructor;
static {
tryImplementation("org.apache.commons.logging.LogFactory", "com.ibatis.common.logging.jakarta.JakartaCommonsLoggingImpl");
tryImplementation("org.apache.log4j.Logger", "com.ibatis.common.logging.log4j.Log4jImpl");
tryImplementation("java.util.logging.Logger", "com.ibatis.common.logging.jdk14.Jdk14LoggingImpl");
tryImplementation("java.lang.Object", "com.ibatis.common.logging.nologging.NoLoggingImpl");
}
private static void tryImplementation(String testClassName, String implClassName) {
if (logConstructor == null) {
try {
Resources.classForName(testClassName);
Class implClass = Resources.classForName(implClassName);
logConstructor = implClass.getConstructor(new Class[]{Class.class});
} catch (Throwable t) {
}
}
}
public static Log getLog(Class aClass) {
try {
return (Log)logConstructor.newInstance(new Object[]{aClass});
} catch (Throwable t) {
throw new RuntimeException("Error creating logger for class " + aClass + ". Cause: " + t, t);
}
}
}
Log4jImpl 是Log 接口的一个实例类,用来实现与log4j的交互
package com.ibatis.common.logging.log4j;
import org.apache.log4j.Logger;
public class Log4jImpl implements com.ibatis.common.logging.Log {
private Logger log;
public Log4jImpl(Class clazz) {
log = Logger.getLogger(clazz);
}
public boolean isDebugEnabled() {
return log.isDebugEnabled();
}
public void error(String s, Throwable e) {
log.error(s, e);
}
......
}
注意到这里最终还是使用了log4j的接口 import org.apache.log4j.Logger;所以说明该jar包在编译的时候还是需要log4j的,但是在实际使用的时候log4j不是必须的,这样就成功去掉了依赖。