Archive for December, 2006
Dec 31
Posted by eDWARD at 15:26
需要Spring 依赖注入的测试
为了测试Spring管理下的Bean,可以自行构造BeanFactory,也可以继承于AbstractDependencyInjectionSpringContextTests,实现public String[] getConfigLocations()函数, 返回applicationContext文件路径的数组。
并显式写一些需要注入的变量的setter函数。
tips1:此基类有一个applicationContext的成员变量,所以除了依靠setter注入外,还可以随时用applicationContext.getBean() 取出所需的bean。
tips2:注意此基类默认是autowire by type的,所以如果context文件里有两个相同类型的Bean就会报错,可能需要在getConfigLocations()函数里,setAutowireMode(AUTOWIRE_BY_NAME);把它设回by name,或者取消setter函数,自行用applicationContext.getBean()来显式查找Bean。
Dao测试
AbstractTransactionalDataSourceSpringContextTests 继承于AbstractDependencyInjectionSpringContextTests,除了拥有上类的能力外,还管理了每个测试的事务,会在每个测试后默认回滚所有的操作。
深层解释,此类的实现其实依赖于Application Context中定义的PlatformTransactionManager。由于使用了autowire by type,可以任意取名。
另依赖于Application Context中定义的DataSource,同样可以任意取名。
tips1:如果需要在测试后提交,需要setRollBack(false); 或者调用setComplete()
tips2:此基类还通过注入的DataSource创建了一个JDBCTemplate 变量,可以跑SQL帮忙核对Hibernate的结果,Spring将确保该查询在同一个事务内执行。为正常工作你需要告诉你的ORM工具’刷新’它的已改变内容,例如使用Hibernate Session 接口的 flush() 方法。
tips3:除了tips2以外,还有countRowsInTable(String tableName),deleteFromTables(String[] names) ,executeSqlScript(String sqlResourcePath, boolean continueOnError)三个简便函数。
Controller测试
Controller测试一般要用MockObject 分离Service层,要copy WEB-INF/下的相关文件copy 到classpath,而且Controller不含太多的逻辑,所有测试controller有点吃力不讨好,建议直接用selenium进行集成测试。见(Selenium测试概述)。
SpringSide里的测试
因为Spring默认的基类名字较长,SpringSide 在core 的org.springside.core.test 中重新继承了它们,并提供了按springside的context文件存放规则,默认读取所有context 文件的getConfigLocations()函数。
默认读取所有context文件的getConfigLocations()函数对速度和测试的隔离化都有影响,可以在子类重新实现。不过自己重新一个个写相关context文件也好烦,而且其实在全lazy-load的情况下,速度也还可以接受。如何取舍要自己平衡了。
对于CRUD的测试,在helloworld示例里的变量名都作了泛化,可以快速copy到另一个测试里。
另外,留意resources/spring/test 下的文件,利用了Spring的PropertyOverrideConfigurer,重新设定测试时的ApplicatonContext 里各个Bean的属性如指定测试用的DataSource,详细用法见Spring配置要点。
phpcode有点排版不便,大家可以看wiki原文。
Sphere: Related Content Filed In 学习路上 | Study | Tags: Spring, 测试, 程序设计 | Add a Comment »
Dec 30
Posted by eDWARD at 15:25
Type1 接口注入
我们常常借助接口来将调用者与实现者分离。如:
上面的代码中,ClassA依赖于InterfaceB的实现,如何获得InterfaceB实现类的实例?传统的方法是在代码中创建InterfaceB实现类的实例,并将起赋予clzB。
而这样一来,ClassA在编译期即依赖于InterfaceB的实现。为了将调用者与实现者在编译期分离,于是有了上面的代码,我们根据预先在配置文件中设定的实现类的类名,动态加载实现类,并通过InterfaceB强制转型后为ClassA所用。
这就是接口注入的一个最原始的雏形。
而对于一个Type1型IOC容器而言,加载接口实现并创建其实例的工作由容器完成,如J2EE开发中常用的Context.lookup(ServletContext.getXXX),都是Type1型IOC的表现形式。
Apache Avalon是一个典型的Type1型IOC容器。
Type2 构造子注入
构造子注入,即通过构造函数完成依赖关系的设定,如:
可以看到,在Type2类型的依赖注入机制中,依赖关系是通过类构造函数建立,容器通过调用类的构造方法,将其所需的依赖关系注入其中。
PicoContainer(另一种实现了依赖注入模式的轻量级容器)首先实现了Type2类型的依赖注入模式。
Type3 设值注入
在各种类型的依赖注入模式中,设值注入模式在实际开发中得到了最广泛的应用(其中很大一部分得力于Spring框架的影响)。
在笔者看来,基于设置模式的依赖注入机制更加直观、也更加自然。Quick Start中的示例,就是典型的设置注入,即通过类的setter方法完成依赖关系的设置。
几种依赖注入模式的对比总结
接口注入模式因为具备侵入性,它要求组件必须与特定的接口相关联,因此并不被看好,实际使用有限。
Type2和Type3的依赖注入实现模式均具备无侵入性的特点。在笔者看来,这两种实现方式各有特点,也各具优势(一句经典废话?)。
Type2 构造子注入的优势:
- “在构造期即创建一个完整、合法的对象”,对于这条Java设计原则,Type2无疑是最好的响应者。
- 避免了繁琐的setter方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈现,更加易读。
- 由于没有setter方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即处相对“不变”的稳定状态,无需担心上层代码在调用过程中执行setter方法对组件依赖关系产生破坏,特别是对于Singleton模式的组件而言,这可能对整个系统产生重大的影响。
- 同样,由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的层次清晰性提供了保证。
- 通过构造子注入,意味着我们可以在构造函数中决定依赖关系的注入顺序,对于一个大量依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要,比如某个依赖关系注入的先决条件是组件的DataSource及相关资源已经被设定。
Type3 设值注入的优势:
- 对于习惯了传统JavaBean开发的程序员而言,通过setter方法设定依赖关系显得更加直观,更加自然。
- 如果依赖关系(或继承关系)较为复杂,那么Type2模式的构造函数也会相当庞大(我们需要在构造函数中设定所有依赖关系),此时Type3模式往往更为简洁。
- 对于某些第三方类库而言,可能要求我们的组件必须提供一个默认的构造函数(如Struts中的Action),此时Type2类型的依赖注入机制就体现出其局限性,难以完成我们期望的功能。
可见,Type2和Type3模式各有千秋,而Spring、PicoContainer都对Type2和Type3类型的依赖注入机制提供了良好支持。这也就为我们提供了更多的选择余地。理论上,以Type2类型为主,辅之以Type3类型机制作为补充,可以达到最好的依赖注入效果,不过对于基于Spring Framework开发的应用而言,Type3使用更加广泛。
Sphere: Related Content Filed In 学习路上 | Study | Tags: Spring, 依赖注入, 控制反转, 程序设计 | Add a Comment »
Dec 28
Posted by eDWARD at 15:22
Spring可以在容器加载时在web.xml中配置filter来进行转发过滤,因为我把html作为screen的映射后缀,所以这里可以根据你的情况设置为*.jsp或*.action等等。
如果你用到了任何properties配置文件,那么就需要通过java/bin/native2ascii统一转码为utf-8编码方式
所有被渲染的view层的页面顶部增加下面的代码
Sphere: Related Content Filed In 学习路上 | Study | Tags: Spring, 乱码, 程序设计 | Add a Comment »
Dec 27
Posted by eDWARD at 15:20
首先是配置文件:(conf/mail.xml)
发送邮件的类:
测试发送类:
Sphere: Related Content Filed In 学习路上 | Study | Tags: Email, Spring, 程序设计 | Add a Comment »
Dec 24
Posted by eDWARD at 15:19
省自身、纠己错是人之为人的基本心理机制,各个成熟的文明皆以反省自身为己之文明向前发展的重要方法,如苏格拉底说的:吾最大的智慧是知道自己无知。一个成熟民族知识群体的中坚力量必能自损己盈满之心,以虚明之怀体察天地默默运行之理。
想起曾经看到过的一篇妙文:“对该起敬的人与事起敬容易,可是讨厌的人和事呢?这个人泼辣多事,爱挑是非,如何以敬待之?那个人自私阴险,机心太重,又如何以敬处 之?还有这件事情无关紧要,做不做都没关系,虽然是好事,做了也没人看见,要不要做?不踏这片草坪的路要绕好远,何况大家都踏着草过,那我要不要也踏?明明家里只有自己一个人,可不可以失态地骂几句脏话,以极不雅的姿势四仰八叉地躺在沙发上?这里处处有挣扎,也就是“慎独”的功夫。太难了。可是我觉得如果真的做到了,人也就真正自由了。想想对待什么人与事的态度都一样,有人看着没人看着行为举止也都一样,如入无人之境,也不会为外界好恶而困扰,真的是自性清静了。自古正道都只有微弱游丝的一条险境而已,走起来当然难,但是一旦走过,便是坦途;歧路却有何止千万条,每一条都看似平坦,真的走了等在前面的就是万丈深渊。”
“儒家的思想是:我不靠超出人之外的外在的力量,不要任何其他人为我的人生命运负责,我只是自己为自己负责。这样当人生失意的时候,就不会怨怪上帝与菩萨:为什么不保佑我呢,或者猜测,让我吃这样的苦头,神的意图是什么呢?所谓不怨天不尤人。如是问的好,那么此生此心安在何处?就安于天地之间,与万物同生灭,与大道共行,逍遥是也。只是这逍遥看似快活,其实更苦更难。儒的慎微与道的逍遥又何尝不是一回事?没有慎微,何来逍遥!没有逍遥的理想与胸襟气度,又有谁受得了慎微?”
“《圣经》里不是也说过了么,通往天国的路如同大象过针眼。如此窄的小道,大家就一路搀扶吆喝着走吧,别把谁给落下。”
你再强大也不要和别人比,你再弱小也要和自己比,你把昨天的自己比下去,你就是强者!是的,今天我的确很弱小,在那些所谓的强者面前,但是我也知道,明天的我会更强,会比今天的我更强。
Sphere: Related Content Filed In 工作路上 | Work, 生活路上 | Life | Tags: 工作, 生活 | Add a Comment »