轻量级开发成功秘诀:露出水面的Spring
【IT168 技术文档】
轻量级容器在为应用程序组织胶水代码方面,提供了一种方法。Spring框架在轻量级容器世界独占鳌头。它内含了轻量级容器、面向方面编程框架和可以轻而易举整合数百种开放源码框架的胶水代码。
在 2003 年的时候,三个山地自行车手和我尖叫着冲下一条叫做 Forrest Ridge 的陡峭小径。这条小径因为刚刚重新开放,没有什么宣传,因此德克萨斯州首府奥斯汀只有很少的人知道它。
整个秋天,我们都保守这个秘密,享受它带给我们的快乐。而到了今天,我们不得不在这条小径上躲避 20 个以上的车手。因为,秘密公开了!
尽管大家发现了这条奇妙的小径对于我和我的朋友而言不是好事,但是,当您的开放源码项目被人发现时,那却是一件令人欣喜若狂的事情。因为从此您就可以更易找到资源、更快修补项目缺陷,并且通常您还可以利用其他的社区资源。
现在,Spring 已经被大家所发现。它是最重要的开放源码项目之一,在企业环境的输入输出中扮演了重要角色,以它自己的方式取得了与 Hibernate 类似的辉煌成果。本文向您展示了 Spring 对于轻量级的开发为何意义如此重大。
Spring 是什么?
您若是一名企业程序开发人员,Spring 会令您事半功倍。但它到底是什么?对于这样的综合性框架,很难轻易找到一个明确的答案。
从本质上讲,Spring 是一个轻量级容器。您可以通过 Spring 来利用普通 Java 对象(POJO)编程,使用依赖注入解析 POJO 间的依赖性,然后使用面向方面编程(AOP)将服务与它们相关联。
Spring 也提供了许多胶水代码,这使您可以更加轻松地使用 Java 2 平台企业版(J2EE)服务,比如用于事务的 Java 事务 API (JTA)、用于远程控制的远程方法调用(RMI)、用于管理的 Java 管理扩展(JMX)或用于持久性的 Java 数据对象(JDO)。
Spring 还为开放源码框架,比如 Hibernate、Tapestry、Struts 和 JavaServer Faces(JSF),提供了胶水代码。注意,虽然有些框架是相互竞争的,但这并不是什么问题,Spring 没有试图只支持一种获胜的框架。
使用 Spring,使您能够利用一些服务。例如,Web Flow 可以轻松地处理 Web 页面间的流。类似地,Web MVC 为类似 Struts 的基于 Web 的应用程序提供了模型-视图-控制器(MVC)架构。
因此,Spring 支持众多的技术。与企业 JavaBean(EJB)技术一样,Spring 容器让您可使用很多企业服务。但是与 EJB 1.x 和 2.x 不一样,放入容器的是 JavaBean,而不是一些私有组件。
与 EJB 脱离的另一方面是,Spring 并不将您限制于少量标准服务,而是让您从大量服务中自由选择,甚至构建您自己的服务。
在我看来,Spring 是 Java 社区中最重要的开放源码项目之一。它帮助我们重新定义了 J2EE。在一定程度上由于来自 Spring 技术革新的压力,导致 EJB 3 专家小组构建了一个比 EJB 2.x 更加相似 Spring 的接口。
我能够轻易地想像到,在企业级程序开发中,Spring 的使用会变得同 Struts 一样普及。为帮助您了解 Spring 如此重要的原因,让我们一层层剥开它神秘的面纱。
核心容器
首先,我们来看看 Spring 的工作原理。在此,我不会为您展示完整的例子,因为您可以找到数不清的 Spring 教程。我使用的是我最新出版的书中的示例应用程序,这里节选示例中的一个片段来向您展示 Spring 可以帮助您所做的事情。
这个应用程序简单地为一个称为 RentaBike 的操作维护一个自行车清单。Spring 是此应用程序的“中枢系统”。Spring 的主要容器 —— 上下文 —— 保存着对所有应用程序主要层和服务的引用。应用程序的主要层是数据库、持久性框架、数据库访问对象和用户界面(UI)控制器及视图层。
这个应用程序的 Spring 上下文只是应用程序使用的 bean 的清单。但是,这些 bean 不是必须依赖所有的 Spring 接口,我在这里选择依赖 Spring 是因为要为您展示一些重复的胶水代码(它们将应用程序联系到一起)。在此上下文中,您会发现至少五种类型的元数据:
·配置 —— 因为容器已经进行了一些配置来处理依赖注入(在 Secrets of lightweight development success, Part 2: How to lighten up your containers 中讲到过),这里有必要也处理其他配置,以便您可以拥有一个方便、一致的策略。
·应用程序的主要层 —— 在 RentaBike 应用程序中,我公开了一个数据访问对象(DAO)层、一个控制器层和一个视图层(参阅清单 1)。我选择将这个 DAO 封装在一个接口中,这样我就能够切换数据访问层来使用不同的持久性策略。
·外部依赖性 —— 例如,我的 DAO 需要一个数据源。Spring 会注入我的 DAO 需要的资源(比如数据源)和平台特定的配置(比如 Hibernate 的会话工厂)。
·透明服务 —— 我们从 EJB 技术中的最大获益之一就是声明性事务。但是您不得不花费大力气得到它们,因为您被强制使用 EJB 接口和重量级 EJB 容器。Spring 让您可以只配置您需要的服务并将它们应用于 POJO。在 Spring 中,您可以使任何方法成为事务型的。
·数据 —— 通常,消息数据、关于应用程序流的信息和测试数据也可能放置在应用程序上下文中。
清单 1. RentaBike 的一部分上下文
<beans>
<bean id="rentaBike" class="com.springbook.JDBCRentABike">
<property name="storeName">
<value>Bruce's Bikes</value>
</property>
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<bean id="bikesController" class="com.springbook.BikesController">
<property name="facade">
<ref bean="rentaBike" />
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost/bikestore</value>
</property>
<property name="username">
<value>bikestore</value>
</property>
</bean>
</beans>
如果仔细观察上下文,您会注意到它是由 bean 组成的。这很重要,因为早期的 J2EE 容器强制您使用给定的 API,具体来说是 EJB。每个 bean 都有一套属性。一些属性是字符串和基本类型值。一些是 bean,比如 rentaBike bean 需要的数据源。您不必实现类似 EJB 会话 bean 接口一样的 API。您只要列出 bean 和它们的属性。其中一些属性满足了依赖性。您现在已经得到了较好的透明性,因此只要需要,您可以在容器之外运行您的 bean 或将您的应用程序移动到其他容器中。
用于测试的上下文
您还可以在上下文中包括其他类型的 bean。例如,使用上下文填充上下文中的简单测试数据或应用程序流是非常有意义的。在 Spring: A Developer's Notebook 中,我们使用存根(它使用数组列表代替数据库)驱动第一个 UI 实现。假如,我们已经得到一个具有姓名和 email 地址的数据库表。我就可以构建一个简单的存根(具有作为属性的数组列表),然后快速实现一些简单数据访问方法,如清单 2 所示。
清单 2. 替换数据库的测试存根
public class StubEmailDirectory {
private List people;
public List getPeople() {
return people;
}
public void setPeople(List people) {
this.people = people;
}
public String findEmail(String name) {
Person p = findPerson(name);
if (p==null) {
return null;
}
return p.getEmail();
}
public Person findPerson(String name) {
if (people==null) {
return null;
}
int size = people.size();
for(int i=0;i<size;i++) {
Person p=(Person)people.get(i);
if(p.getName().equals(name)) {
return p;
}
}
return null;
}
}
然后,我可以从上下文填充它,如清单 3 所示。
清单 3. 上下文中的测试数据
<beans>
<bean id="bruce" class="j2life.bus.Person">
<property name="name">
<value>Bruce</value>
</property>
<property name="email">
<value>bruce.t@j2life.com
</value>
</property>
</bean>
<bean id="maggie" class="j2life.bus.Person">
<property name="name">
<value>Maggie</value>
</property>
<property name="email">
<value>maggie.t@j2life.com
</value>
</property>
</bean>
<bean id="emails" class="j2life.bus.StubEmailDirectory">
<property name="people">
<list>
<ref bean="bruce"/>
<ref bean="maggie"/>
</list>
</property>
</bean>
</beans>
当您考虑测试时,从上下文中摘出测试数据常常很有意义。为使测试用例可重复和可验证,您可以从上下文而不是服务摘出不可预知的数据(例如,系统时间和随机数)。Spring 的上下文使测试更加容易,因为您可以通过不同方法为生产和测试配置应用程序。
Spring 的基础是容器,并且这个基础很重要。但容器远不能代表它的全部。
0
相关文章