MyBatis 想要打印日志,时不时想要来句 log.debug() 、log.error() ,需要个打印机 ,可是自己又不想去实现(而且跟着整个项目用同样的打印系统才是王道啊),需要去用别人家的打印机,要用别人家的产品啊,那问题可就来了。
# 问题 1
市面上各家的打印机 slf4j、java.util.logging、log4j 甚至 System.out 都是各种不同的用法,这使用起来就太麻烦了。
# 思路
不管市面上打印机有多少型号,我家 MyBatis 包里的类只用自家的统一接口,我家的类只管 log.debug()、log.error()…
定义好了接口,就需要实现类 impl 来实现这些 debug()、error() 方法了 , 咱假装是自己来实现,其实去调用真正打印机 slf4、log4j 的方法,这样就把别人家的打印机和咱自家的接口关联起来啦。
这就是适配器模式。
我家的每个实现类其实就是一个适配器,每个适配器去适配一种打印机。比如 slf4jLoggerImpl 就完成了对 slf4j 打印机的适配,slf4jLoggerImpl .debug() 调用了slf4j.Logger.debug()。
这样市面上每多一种打印机,比如想用 log4j2 了,我就只需要加一种适配器 log4j2LoggerImpl 去适配它就可以了。
# 代码
定义接口
|
|
在实现类里完成适配,比如适配 slf4j 的 Slf4jLoggerImpl
|
|
# 问题 2
适配器咱是做好了,slf4j、log4j、stdout…做了那么多适配器,可是怎么用啊?我真正要打印机的时候,怎么才能知道我该调用哪款适配器啊?难道每次取打印机的时候,都去查一遍咱的系统配了那款打印机(jar) 包么?而且以后多加了1种打印机,我还去每个地方都改一遍,都多加一道判断么?
# 思路
这其实就是获取实例的时候的问题,咱获取实例太累了,不如来个统一的工厂吧,我每次想打印的时候,都去找工厂要一台打印机,你工厂按照我 Log 的接口给我一个实例就是了。我也不管你给的具体实现到底是 slf4j 家的,还是 log4j 的,甚至可能是 NoLoggingImpl
每次调接口都不处理的这种空壳打印机。
这样一来,有了统一的工厂,判断系统用哪种适配器的任务就可以在工厂完成了。
而且以后就算新加了打印机,也只要改改工厂的代码,在工厂里多加一重判断就可以了。
这就是工厂模式。
# 代码
|
|
LogFactory 提供了对外的 getLog(String logger) 方法,给需要 logger 的地方提供一个 Log 的实例。
内部的实现依靠 logConstructor
这个构造器通过反射来实例化一个 Log 的 Impl ,也就是之前的适配器,比如 Slf4jLoggerImpl 。
判断采用哪种logConstructor
的任务则在类初始化的时候就执行了,依次尝试了我们的每一款适配器,碰上报错就说明没 jar 包,下一款,全都没有的话,就用 NoLoggingImpl 了。