论坛首页 Java版

怎样用spring来重构这样一个遗留系统?

浏览 11435 次
该帖已经被评为良好帖
作者 正文
最后更新时间:2006-10-31
我们现在经手的这个系统,有这么一个非常非常核心的类:
ImplFactory。它有一个非常非常核心的方法:
ImplFactory.newClass(Class type, Object[] args);



这个方法什么意思呢?基本上和调用new type(arg1, arg2, ...)差不多。只不过是动态的,类型不安全的。
为什么要这么做呢?其本意是,后面有一个ImplFactory.properties文件,当调用newClass(MyType.class, new Object[]{a,b,c})的时候,ImplFactory会先检查ImplFactory.properties,如果发现MyType有个子类被登记了,就用那个子类,否则就用MyType本身。无论如何,args都会被作为构造函数的参数传入。

有些对newClass()的调用非常复杂冗长。比如系统某些地方要对某个service包裹一层logging支持,那么要先用newClass找到logger instance,然后用newClass找到这个service,最后还要用newClass来把这个logger和service封装到一个LoggedService(或者子类)中。

这个系统的另外一个讨厌的地方是,到处出现的appId和sessionId两个变量。这两个变量根据程序的上下文值会不同。而在调用ImplFactory.newClass的时候50%的情况需要传递这两个变量,很烦琐。

现在,考虑用spring重构。难点为:
    1。希望能够暂时不动ImplFactory.properties文件。因为大家(包括客户)已经习惯于用它了。最好能在spring.xml里面写:
    <include properties="ImplFactory.properties"/>
    

    然后额外的一些比较复杂的组装比如logging,用spring xml来搞。
    2。希望保留系统原来的缺省类型语义,配置文件可以只用来配置customization。有时候如果newClass(MyClass.class)的这个MyClass不需要提供一个子类,可以直接用new MyClass(),而不是要求必须在spring xml里面配置MyClass。
    3。无论spring如何配置,希望允许参数从外部传递进来。newClass(MyClass.class, new Object[]{a,b})希望能够把a和b传递给被spring配置的组建类。
    4。appId和sessionId的传递很烦琐,希望能够把它们作为所有组件的全局变量。而不用每次都传递。(这样可以减少多于一半的传递额外参数的需要了)而如果作为全局变量,希望不同上下文的不同值能够被正确反映,而且线程安全,而且不严重影响并发性。


最后,如果这些需求都能做到,我就可以用dynamic proxy,那container实现一个强类型的ServiceFactory,最终客户的调用代码会变成:
MyClass mc = factory.getMyClass();
MyService service = factory.getMyService(a, b);

然后再把ServiceFactory注射到使用ImplFactory的类里面来代替它,就算搞定了。


我是暂时还没有发现用spring怎么实现这些需求,用yan倒是可以。正好借着spring讨论的热乎劲儿,请spring的专家给鉴定鉴定。
   
最后更新时间:2006-11-01
我们也正想大规模重构系统
把ejb从系统中踢出去
但是一点头絮都没有
如果可能把你的过程写成blog好不好
PS:可不可以加我为好友
   
0 请登录后投票
最后更新时间:2006-11-01
1,2,3这么理解?

调用: ImplFactory.newClass(Class type, new Object[]{a,b});

ImplFactory.properties里面有
MyType=DefaultMyTypeImpl.class

spring.xml里(这个配置是随手写的):
<bean id="任意" class="DefaultMyTypeImpl">
    <constructor-arg index="0">${0}</constructor-art>
    <constructor-arg index="1">${1}</constructor-art>
    <constructor-arg index="2">
       <ref bean="其它spring组件"/>
    </constructor-art>
</bean>

这些组件要注入其它bean吗?
   
0 请登录后投票
最后更新时间:2006-11-01
nihongye 写道


1,2,3这么理解?

调用: ImplFactory.newClass(Class type, new Object[]{a,b});

ImplFactory.properties里面有
MyType=DefaultMyTypeImpl.class

spring.xml里(这个配置是随手写的):
<bean id="任意" class="DefaultMyTypeImpl">
    <constructor-arg index="0">${0}</constructor-art>
    <constructor-arg index="1">${1}</constructor-art>
    <constructor-arg index="2">
       <ref bean="其它spring组件"/>
    </constructor-art>
</bean>

这些组件要注入其它bean吗?

比如调用newClass(com.mycom.MyType.class, new Object[]{a,b})的时候,如果properties文件没有对com.mycom.MyType登记,那么直接调用new MyType(a,b);
而如果有,比如:
com.mycom.MyType=com.mycom.MySubType
那么就new com.mycom.MySubType(a,b)

最终当这个properties文件不用了,或者我们选择在appcontext.xml中配置比较复杂的组件,比如你的例子中的那个,希望客户接口不变。还有,如果这个DefaultMyTypeImpl需要用appId,希望能这么写(或者等价的方法)
<bean id="任意" class="DefaultMyTypeImpl">
    <constructor-arg index="0">${appId}</constructor-art>
    <constructor-arg index="1">${0}</constructor-art>
    <constructor-arg index="2">${1}</constructor-art>
    <constructor-arg index="3">
       <ref bean="其它spring组件"/>
    </constructor-art>
</bean>

这个组件有可能注入其它bean的,至少我们不希望被剥夺这个可能性。
   
0 请登录后投票
最后更新时间:2006-11-01
哦,明白了,要学习一番spring才知道,现在只知道从ApplicationContext下手,但里面那套复杂的wire,parent,child context不知道是怎样的。
   
0 请登录后投票
最后更新时间:2006-11-01
说明一下,

1不是必要的。如果不好弄,大不了我自己写代码读这个property文件然后自己登记appcontext。关键是2,3,4。如果做不到,spring就只能被枪毙了。

关于3,柞一想似乎不合理。难道要求所有的子类都必须接受a,b两个参数?可仔细一想,存在的就有其合理性。也许不是所有的实现都必然需要接受这两个参数,但是至少典型的实现都要这两个参数。

我用yan实现这个功能的时候,如果配置的实现类不需要这两个参数,也没关系,程序会自动忽略传进来的参数。

从spring的BeanFactory接口来看,目前似乎做不到。它只有getBean(beanName),而没有办法额外传递参数。

所以目前我只实现了yan的prototype,spring和pico都还没着落呢。
   
0 请登录后投票
最后更新时间:2006-11-01
自己扩展一个spring的BeanFactory类,在afterpropertyset方法里添加自己想要的参数咯!
   
0 请登录后投票
最后更新时间:2006-11-01
hgbjava 写道
自己扩展一个spring的BeanFactory类,在afterpropertyset方法里添加自己想要的参数咯!

有点怀疑你自己都不知道自己在说什么。
afterpropertiesset是对象已经创建了之后才调用的,怎么可能处理构造函数的参数?
扩展BeanFactory又能和afterpropertieset扯上什么联系?
   
0 请登录后投票
最后更新时间:2006-11-01
ajoo 写道
hgbjava 写道
自己扩展一个spring的BeanFactory类,在afterpropertyset方法里添加自己想要的参数咯!

有点怀疑你自己都不知道自己在说什么。
afterpropertiesset是对象已经创建了之后才调用的,怎么可能处理构造函数的参数?
扩展BeanFactory又能和afterpropertieset扯上什么联系?


写一个spring的FactoryBean,在配置文件里可以随意配置你需要的参数,在这个factorybean中再去创建你实际需要的对象,这只不过是可以实现从配置文件里读取属性而已。
   
0 请登录后投票
最后更新时间:2006-11-01
引用
从spring的BeanFactory接口来看,目前似乎做不到。它只有getBean(beanName),而没有办法额外传递参数。

所以目前我只实现了yan的prototype,spring和pico都还没着落呢

我的思路是这样的,实现一个称为
ThreadSafeApplicationContext的context
ImplFactory的实现是这样的:
context.register( type,args );
context.register( "sessionId",sessionId );
return context.getBean(type);
另外:spring再怎么整也比不了yan的设计啊...哈哈。
   
0 请登录后投票
论坛首页 Java版

跳转论坛:
JavaEye推荐