Archive for December, 2006

Spring的项目测试的一些要点

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: , , | Add a Comment »

Spring框架中的三种注入方式

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 构造子注入的优势:

  1. “在构造期即创建一个完整、合法的对象”,对于这条Java设计原则,Type2无疑是最好的响应者。
  2. 避免了繁琐的setter方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈现,更加易读。
  3. 由于没有setter方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即处相对“不变”的稳定状态,无需担心上层代码在调用过程中执行setter方法对组件依赖关系产生破坏,特别是对于Singleton模式的组件而言,这可能对整个系统产生重大的影响。
  4. 同样,由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的层次清晰性提供了保证。
  5. 通过构造子注入,意味着我们可以在构造函数中决定依赖关系的注入顺序,对于一个大量依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要,比如某个依赖关系注入的先决条件是组件的DataSource及相关资源已经被设定。

    Type3 设值注入的优势:

  1. 对于习惯了传统JavaBean开发的程序员而言,通过setter方法设定依赖关系显得更加直观,更加自然。
  2. 如果依赖关系(或继承关系)较为复杂,那么Type2模式的构造函数也会相当庞大(我们需要在构造函数中设定所有依赖关系),此时Type3模式往往更为简洁。
  3. 对于某些第三方类库而言,可能要求我们的组件必须提供一个默认的构造函数(如Struts中的Action),此时Type2类型的依赖注入机制就体现出其局限性,难以完成我们期望的功能。

  可见,Type2和Type3模式各有千秋,而Spring、PicoContainer都对Type2和Type3类型的依赖注入机制提供了良好支持。这也就为我们提供了更多的选择余地。理论上,以Type2类型为主,辅之以Type3类型机制作为补充,可以达到最好的依赖注入效果,不过对于基于Spring Framework开发的应用而言,Type3使用更加广泛。

Sphere: Related Content

Filed In 学习路上 | Study | Tags: , , , | Add a Comment »

Spring中关于乱码的解决办法

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: , , | Add a Comment »

用Spring的MailSender和MailMessage发送邮件(Email)

Posted by eDWARD at 15:20

首先是配置文件:(conf/mail.xml)

发送邮件的类:

测试发送类:

Sphere: Related Content

Filed In 学习路上 | Study | Tags: , , | Add a Comment »

吾日三省吾身,为人谋而不忠乎?与朋友交而不信乎?传而不习乎?

Posted by eDWARD at 15:19

  省自身、纠己错是人之为人的基本心理机制,各个成熟的文明皆以反省自身为己之文明向前发展的重要方法,如苏格拉底说的:吾最大的智慧是知道自己无知。一个成熟民族知识群体的中坚力量必能自损己盈满之心,以虚明之怀体察天地默默运行之理。

  想起曾经看到过的一篇妙文:“对该起敬的人与事起敬容易,可是讨厌的人和事呢?这个人泼辣多事,爱挑是非,如何以敬待之?那个人自私阴险,机心太重,又如何以敬处 之?还有这件事情无关紧要,做不做都没关系,虽然是好事,做了也没人看见,要不要做?不踏这片草坪的路要绕好远,何况大家都踏着草过,那我要不要也踏?明明家里只有自己一个人,可不可以失态地骂几句脏话,以极不雅的姿势四仰八叉地躺在沙发上?这里处处有挣扎,也就是“慎独”的功夫。太难了。可是我觉得如果真的做到了,人也就真正自由了。想想对待什么人与事的态度都一样,有人看着没人看着行为举止也都一样,如入无人之境,也不会为外界好恶而困扰,真的是自性清静了。自古正道都只有微弱游丝的一条险境而已,走起来当然难,但是一旦走过,便是坦途;歧路却有何止千万条,每一条都看似平坦,真的走了等在前面的就是万丈深渊。

  “儒家的思想是:我不靠超出人之外的外在的力量,不要任何其他人为我的人生命运负责,我只是自己为自己负责。这样当人生失意的时候,就不会怨怪上帝与菩萨:为什么不保佑我呢,或者猜测,让我吃这样的苦头,神的意图是什么呢?所谓不怨天不尤人。如是问的好,那么此生此心安在何处?就安于天地之间,与万物同生灭,与大道共行,逍遥是也。只是这逍遥看似快活,其实更苦更难。儒的慎微与道的逍遥又何尝不是一回事?没有慎微,何来逍遥!没有逍遥的理想与胸襟气度,又有谁受得了慎微?

  “《圣经》里不是也说过了么,通往天国的路如同大象过针眼。如此窄的小道,大家就一路搀扶吆喝着走吧,别把谁给落下。

  你再强大也不要和别人比,你再弱小也要和自己比,你把昨天的自己比下去,你就是强者!是的,今天我的确很弱小,在那些所谓的强者面前,但是我也知道,明天的我会更强,会比今天的我更强。

Sphere: Related Content

Filed In 工作路上 | Work, 生活路上 | Life | Tags: , | Add a Comment »

Page 1 of 3123»
Technorati

  品位不凡,威严,略显高深,喜爱一切美丽的事物,易怒,固执,有些利己,但关心接近他的人。谦逊,但非常有野心,有才能,刻苦,是不甚令人满意的伴侣,朋友众多,树敌也多,是可以信赖的人。


bloglines
google reader
my yahoo
订阅我的博客