日志,在传统的java程序中都从来不是问题,差点的有jdk的 logging package ,俗点的有 commons logging 和 log4j ,潮点的也有 slf4j 和 logback,哪一个不是独当一面,哪个不是顺手拈来,哪个不是极尽性能和方便的能事。
但是,前提是简单而单纯的classloader,传统的java大多是一个classloader跑到底,所以这些 logging api 个个都天下无敌,没有任何意外的被使用着。
当编程从单线程变成多线程模型的时候,噢,程序跑快了,但是却让很多程序员抓成地中海了。同理,当单classloader变成多classloader的时候,哦,程序模块化了,但是让更多的程序员抓狂不已了,就连以前简单的 logging api 都欺负起他们来了。
logging从来都被当成是一种全局化的服务,当全局化碰到模块化,me也只能仰天长叹:顶君肺!!
然后继续埋头研究解决方法:
方法一:
把logging服务当成是局部服务,每个bundle都自带自己logging api,就是当单classloader使用了,没啥好说,只要你能忍受万国牌 logging api,或者不断重复再重复的导入和配置。
方法二:
OSGi本身也定义了自己的LogService,你把它当成是你的全局化logging实现就好了,听上去还挺顺心的,暗喜OSGi还是留了一条活路给你了,还不快点磕头谢恩。
噢,等等,你当全天下是你OSGi的天下了吧,多少程序都使用着其他的logging api呢,你数数你写过多少行类似这样的代码再说吧
Log logger = LogFactory.getLog( MyPojo.class );
数不出来吧,把全世界像你一样的蚁民程序员加起来,+∞了吧,那LogService算啥鸟啊。
神啊,给条活路吧,还是会有好心人做点脏活为人民服务的,看这里就有这么个sb:Pax+Logging
具体请看
http://wiki.ops4j.org/confluence/display/ops4j/Pax+Logging 大概就是:用log4j去实现那个LogService,然后把所有各大logging api都重新包装一遍,转向调用LogService。所以他有一个包含LogService的bundle。还有一个logging api,它的包结构正好跟各大流行的logging一致,例如有org.apache.log4j.Logger和org.apache.commons.logging.Log等这样的类,不过已经是挂羊头卖狗肉了,全是一律转向LogService的调用。自己的bundle 用log的时候,以前的怎么写现在还是怎么写,不过要加上OSGi风格的信息就可以了:
Import-Package: org.apache.log4j; version="[1.2,1.3)"; provider=paxlogging,
org.apache.commons.logging; version="[1.0,1.1)"; provider=paxlogging
你用哪个就import哪个,以下的他都支持
* Log4J driving the backend implementation.
* Log4J API supported.
* Jakarta Commons Logging API supported.
* Pax Logging Service implements the standard OSGi Log Service API.
* JDK Logging API support.
* Avalon Logger API support.
* SLF4J API support.
* Knopflerfish Log service support.
* Tomcat Juli API support.
但假如你的bundle的classpath下有正版的logging api怎么办,翻版货如果没被选上那不就不行了,难道还要求神拜佛一定要选上那个翻版的api不成,其实OSGi的优势又可以让他发挥一下了,上面的Import-Package写法,后边还跟一个provider=paxlogging,言下之意就是说打有paxlogging标记的才是翻版货。
方法三:
假如你拒绝翻版要用正版的logging api。ok,值得鼓励。
新建一个log bundle,不同的是我们不是使用LogService了,而是使用
slf4j,其实slf4j只是一个facade,不过他为各路正版logging api提供了桥梁,也就是说无论你采取log4j还是common logging的代码写法,通过这些桥,你都可以log了。
为什么同为facade,slf4j可以做到而commons logging不能,要从他们运作机理谈起了。
commons logging使用了Thread的ClassLoader寻找和载入底层的日志库。虽然自动,一听到ClassLoader,你就知道他在OSGi环境下死路一条了。
slf4j库在编译时静态绑定真正的Log库。使用slf4j时,如果你需要使用某一种日志实现,那么你必须选择正确的slf4j的jar包的集合。
简述如下,那个slf4j bundle要具有以下的OSGi定义
Bundle-ClassPath: bin/, lib/jcl104-over-slf4j-1.3.1.jar, lib/slf4j-api-1.3.1.jar, lib/log4j-1.2.14.jar, lib/slf4j-log4j12-1.3.1.jar
Export-Package: org.apache.commons.logging, org.apache.log4j, org.apache.log4j.spi, org.apache.log4j.xml, org.slf4j
其他需要log的bundle具有类似以下的OSGi定义
Import-Package: org.apache.log4j, org.apache.commons.logging, …
再次顶君肺一下以示发泄!