CowNew开源团队网站http://www.cownew.com
论坛http://www.cownew.com/newpeng/
转载请注明此版权信息
昨天发现JDBMonitor在多数据源的情况下会有问题,这个问题就是对单例模式理解不深造成的。为了减少系统中的对象数目,我用单例模式设计DBLogger,也就是提供一个getLogger方法返回一个日志处理器,getLogger则返回的是一个缓存了的DBLogger实例。昨天我用一个大型的信息系统测试了一下,发现当有多个数据源存在的时候,所有的日志都记录到了第一个启动的JDBMonitor的配置文件指定的监听器中了。经过分析得知,虽然多个数据源启动了多个JDBMonitor,但是由于这些JDBMonitor实例是运行在同一个JVM中的,而一个类变量在同一个JVM是唯一的,所以这些实例调用getLogger的时候得到的都是第一个JDBMonitor中配置的了。
我采用如下方式解决:为getLogger增加一个connectionId参数,将原先的单例去掉,改成一个hash表的静态变量instanceMap。在调用getLogger的时候,先以connectionId为key到instanceMap中找是不是已经有一个实例了,如果有则直接返回这个实例,否则构造一个DBLogger,将此DBLogger以connectionId为key保存到instanceMap中,然后返回实例。
根据JDBMonitor的功能特点配置文件的路径就可以做为这个connectionId了,也就是如果是多个数据源指向一个配置文件,那么这几个数据源其实还是共用一个DBLogger,这个也是合理的,而且也可以节省很多资源。
从这个例子我们可以看出,单例模式并不一定是只创建一个实例这么简单。Log4j的getLogger就是很好的证明。
但是多个数据源共用一个DBLogger又引来了另一个问题,就是当有一个数据源的Connection被close掉以后,DBLogger也会随之close掉,其他数据源再访问的时候就会报错。我采用类似GC、COM等的引用机制解决此问题。在DBLogger内部维护一个计数器refCounter,初始值是0,当调用getLogger访问到此实例的时候,就refCounter自动加1,当调用DBLogger的close的时候就自动减1,当refCounter降到0的时候就说明没有对象引用到它了,这个时候再释放DBLogger中的各种资源。当然addRef、releaseRef、close等方法都要标识成synchronized的。
同理,以前的这些channel、dbListeners类变量也要改成实例变量。consumerthread也要改成实例变量,在close中再关闭这个线程。这样就保证了每一个JDBMonitor都有自己的消费者线程。
为了使语意更加明确,我将getLogger重命名为createLogger。
代码已经提交到CVS,今天晚些时候将打包放到团队网站上。
向大家汇报,SQL解析引擎已经有阶段成果,强类型AST节点都已定义完毕,也已经可以生成最简单的CommonAST。