第一次发贴,想问一下有没有可能在运行时重新加载一次spring的singleton类?

05-02-16 warbaby
直接说目的吧,我用spring+ibatis的组合,通过分析,发现spring框架是通过用SqlMapClientFactoryBean读取sql-map-config.xml生成SqlMap的singleton。

我有一个异想天开的想法,就是,如果能够把这个单例类销毁,然后再重新构造一次,那样,岂不是可以在运行时修改sql-map-config.xml及相应的sql-map.xml而实时的反映结果?

我真的不知道这个问题是不是会让各位老大发笑。但是我想,既然spring可以lazy加载一个singleton,那么关键就在于如何销毁一个singleton。

而我对singleton的理解就是,它维护了一个uniqueInstance。只要能把这个uniqueInstance给设置为null,那么就相当与销毁了。但是一般这个都是被封装成private的了,不知道有没有什么超常规的方法可以做到这一点。

衷心感谢能为我思考这个问题的各位~~~

1
warbaby
2005-02-17 00:18
通过一晚上的努力,终于成功了。但是个人认为解决的很丑陋。过程如下(请看完,最后有个说明)

1、增加一个ReloadableSqlMapClientFactoryBean,从spring的SqlMapClientFactoryBean复制所有代码

2、给这个FactoryBean增加public void reload()方法,两行:

this.setConfigLocation(new FileSystemResource(this.configLocation.getFile().getPath()));

this.afterPropertiesSet();

3、将applicationContext.xml中的sqlMapClient的class设置为ReloadableSqlMapClientFactoryBean

4、在自己的WEB程序下建立com.ibatis.common.resources.Resources类,不用说,拷贝人家原来的代码过来。

5、修改Resources.getResourceAsStream(ClassLoader loader, String resource),将

<<<<<<loader.getResourceAsStream(resource);//换成

>>>>>>loader.getResource(resource).openStream();

6、写一个jsp文件,得到ReloadableSqlMapClientFactoryBean,然后调用其reload方法,即可刷新。

在跟踪调试的过程中,主要遇到两个关卡:

一,第二步的第一行,是为了确保重新读取sql-map-config.xml。

二,前3步都很好理解,但是后面的就读了很久代码才搞明白。原来catalina的WebappClassLoader的getResourceAsStream是先读缓存(看tomcat的api可以知道),而iBatis是用这个方法来读取sql-map.xml的,导致配置文件内容被缓存。而用loader.getResource就可以。

在一个Web应用程序中,只在SqlMapClientBuilder中才会读取这些配置文件,一般情况下,只在启动时在调用,所以这样修改对实际应用没有任何影响。

我现在对java还没有什么实践经验,请各位前辈帮忙分析一下,这样做有没有意义?是否有什么隐患?或者有什么更帅的解决方法呢?

(BTW:可能有人会说“这样做根本没有任何价值”,因为业务模型应该是先经过测试并稳定的,sql映射在运行时不应该有任何改动。我自己也明白呵呵,但是觉得如果能实时的修改出来,不是更好吗?现在在IDE环境中,Class有时都能HotLoad,配置就更应该能手动刷新吧。。。。)

banq
2005-02-17 21:09
首先,你的探索精神值得肯定,就应该这样动手去做。最后,你得出这样结论:

>在SqlMapClientBuilder中才会读取这些配置文件,一般情况下,只在启动时在调用

在系统启动时调用,这是一般Ioc模式实现的一个基本条件,Ico实现调用和被调用的解耦,但不是完全消灭,而是转移,转移到了例如系统启动时实现。

从另外一个方面说:xml配置一般也应该是启动时获取,然后实现缓存,这样才能提高性能。

看来你的具体问题要靠其它方式优雅地来解决了。

猜你喜欢