Spring的巧妙之处
作者注:在《Better, Faster, Lighter Java》一书第八章的这份节录中,我们将看到一个使用Spring框架的企业web应用程序例子。尽管Hibernate提供了单个的服务,Spring框架却提供了一种高效地构建和汇编Java应用程序的方法,以及多种服务的抽象。尽管Spring支持多种服务,但是它最受关注也是最出色的特性是杰出的分层和封装。与EJB一样,Spring的中心组件是一个容器;而且Spring框架也同样提供对核心J2EE服务的访问。但是这就是它们仅有的相似之处了。下面是一个比喻。 我喜欢皮划艇运动,也花了很多时间来教授皮划艇技巧。我的一个专长就是教授学生如何在浪花中翻转弄翻了的皮划艇。一天,我向一位四肢发达的大个子和一位玲珑瘦小、体重只有97磅的女士传授该技巧。当我在陆地上从头到尾仔细地讲述这项技巧的时候,大个子直勾勾的盯着远方,不感兴趣。而那位女士注意力集中,而且希望反复练习这项基础技巧。在半个小时之内,她就出色地完成了第一次翻转,而他只是上下摇摆,在平静的水面上拍打出细小的白色泡沫。直到第三个学时,他才完成这个动作。在以后的几个学时中,她依靠技巧快速提高,而他却单凭力量在水中挣扎。到了实践的时候,她翻转了皮划艇,而他却在游泳。程序员们,请记住:解决问题的最佳方式是依靠简单性和技巧,而不是蛮力。 Pet Store:一个反例 基准纷争过后,很多人借助于更平易且更简单的技术来实现Pet Store。其中一种最强大且最简单的实现方法是Clinton Begin所使用的,他利用一个称为iBatis的DAO框架来代替全部的实体bean。Rod Johnson的团队将该应用程序转化为Spring,并且现在已经与Spring框架一起发布。以下是相关的一些细节:
在下面的部分中,我将演示具有MVC web前端和单个数据库中的简单事务的应用程序版本。我将重点讨论域模型、单数据库DAO层、单一事务以及Spring MVC前端。Spring网站上提供了大量的资源,可供希望深入研究的开发人员使用。 配置文件 很多J2EE应用程序借助单元素来了解诸如连接之类的应用程序资源。这种用途的单元素与很多Java开发人员经常使用的全局变量差别不大。J2EE中的替代方案是一种称为JNDI的目录服务,但是对于许多常见用例来说它就是杀鸡的牛刀了。而Spring使用一种应用程序上下文。最初,需要在一个简单的XML文件中指定应用程序上下文,尽管也可以通过扩展Spring来接受其它类型的配置文件。以下是应用程序上下文中可能会包含的内容: 数据源 DAO层 持久性管理器 事务策略 事务管理器 验证逻辑 视图和控制器 jPetStore应用程序使用包含一个数据源、DAO层和一种事务逻辑的Spring应用程序上下文。用户定义XML文档中上下文的内容,该XML文档列出了一系列bean。每一个XML配置文件都包含一个<beans>题头,其后是一系列<bean>组件和一个</beans>脚注。如下所示: <beans> <bean id="MyFirstBean" class="package.MyFirstBeanClass"> <property name="myField" ref local="MySecondBean"/> </bean> <bean id="MySecondBean" class="package.MySecondBeanClass"> </bean> </beans> 以上是构成应用程序上下文的bean。它们代表应用程序中的顶级bean。(它们可以创建不出现在配置文件中的其他对象或bean。)在本例中,我们会创建两个bean:MyFirstBean和MySecondBean。然后,通过指定MySecondBean作为字段myField的值,将它们关联起来。当Spring启动的时候,它会创建两种对象,并设置myField的值。当在应用程序上下文中需要它们的时候,可以根据名称来访问这两种对象。 我们来看一个更具体的实例。jPetStore应用程序为业务逻辑、数据层和用户界面提供了三种配置文件,每种Spring配置文件各自描述三者之一,如图8-2所示。
这些配置文件指定了域模型、数据层和表示层的上下文。例8-1展示了jPetStore应用程序的业务逻辑应用程序上下文的一部分。注意:为了简单起见,我将包名org.springframework.samples.jpetstore...缩写为jpetstore。 例8-1 applicationContext.xml <beans> [1] <bean id="accountValidator" class="jpetstore.domain.logic.AccountValidator"/> [2] <bean id="orderValidator" class="jpetstore.domain.logic.OrderValidator"/> [3] <bean id="petStoreTarget" class="jpetstore.domain.logic.PetStoreImpl"/> [4] <property name="AccountDao"><ref bean="accountDao"/></property> <property name="categoryDao"><ref bean="categoryDao"/></property> <property name="productDao"><ref bean="productDao"/></property> <property name="itemDao"><ref bean="itemDao"/></property> <property name="orderDao"><ref bean="orderDao"/></property> </bean> [5] <bean id="petStore" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref bean="transactionManager"/></property> <property name="target"><ref bean="petStoreTarget"/></property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean> </beans> 以下是对注释的解释: [1]业务逻辑。这部分(包括所有粗体代码)包含核心的业务逻辑。验证和域模型都视为业务组件。 [2]验证器。这是Order的验证器。一旦用户提交Order格式,并发送到错误页面或order完成页面,Spring就会按照要求调用该验证器。 [3]核心业务实现。该类包含持久性域模型的核心实现。它包含以下所有的DAO对象。 [4]属性。每一个bean都具有自己的属性,这些属性引用定义在其他地方的bean。在本例中,bean属性是单个的DAO。每一个bean都定义在另一个Spring配置文件中。 [5]事务声明。这个bean指定了应用程序的事务策略。在本例中,应用程序使用在另一个Spring配置文件中指定的事务管理器。它声明了应当传播为事务的方法。例如,所有以insert开头的方法应当传播为事务。 简而言之,该配置文件就像一种粘合剂,将应用程序的业务逻辑粘合在一起。在文件中,您会看到一些对本身并未包含在配置文件中的bean(如:DAO对象)的引用。随后,您会看到其他两种配置文件,它们定义了一些遗漏的bean。其中一个配置文件指定了事务管理器的数据访问对象。另一个配置文件指定了用户界面所需的bean。最好将配置文件分离到不同的层中,这样就可以按照需要配置各个层。例如,可能需要更改用户界面的策略(比如从Spring MVC web更改为Strut),或者数据访问的策略(比如从具有单个数据库的DAO更改为具有JTA事务、跨两个数据库的DAO)。 如果需要实例化XML上下文文件中的bean,那么非常简单。例如,要访问context.xml文件中Customer类型的名称为myCustomer的bean,可以采用以下三个步骤:
InputStream stream = getClass( ). getResourceAsStream("context.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(stream);
Customer cust = (Customer)beanFactory.getBean(myCustomer); 或者,如果希望Spring初始化一个上下文,然后抓取会话外观,可以使用以下代码: protected static final String CONTEXT_FILE = "WEB-INF/applicationContext.xml"; Biz biz; // session façade FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(CONTEXT_FILE); biz = (Biz) ctx.getBean("biz"); 最好放开控制权。通常不必直接访问应用程序上下文。框架会执行该操作。例如,如果您正在使用servlet,那么Spring框架会为每一个servlet提供一个上下文,并为所有servlet提供一个总体上下文。通常可以从中获得正确的上下文信息,随后您就会看到这一点。既然已经看到了表示jPetStore应用程序的配置文件,现在应该看看如何构建各个元素: 域模型
应用程序表示了一个简单的宠物商店。它由一个包含购物车项目(cart item)的购物车组成,该购物车又填充了一个包含线项目(line item)的订单。项目(item)由按类别(category)组织的产品(product)组成。每个对象都是一个透明的业务对象,被实现为具有一些属性和业务方法的Java bean。例8-2展示了一个CartItem。为了简单起见,我已经去掉导入和包细节。 例8-2CartItem.java [1] public class CartItem implements Serializable { /*Private Fields*/ private Item item; private int quantity; private boolean inStock; /*JavaBeans Properties*/ [2] public boolean isInStock() { return inStock; } public void setInStock(boolean inStock) { this.inStock = inStock; } public Item getItem( ) { return item; } public void setItem(Item item) { this.item = item; } public int getQuantity( ) { return quantity; } public void setQuantity(int quantity) { this.quantity = quantity; } [3] public double getTotalPrice() { if (item != null) { return item.getListPrice( ) * quantity; } else { return 0; } } /*Public methods*/ public void incrementQuantity( ) { quantity++; } } 以下是注释的含义: [1]Spring框架不会强迫组件继承Spring类。它们是完全透明的,并且如果进行测试或者情况需要,还可以驻留在容器的外部。 [2]每一个字段都使用get和set方法进行包装,以便Spring可以通过Java反射来配置他们。(Spring还可以通过构造函数来配置它们。) [3]与很多EJB应用程序不同,在域模型中包含业务域逻辑非常有用。 我将这种模型称作passive。它完全由域外面的对象调用,并且仅与域中的其他对象耦合。注意,虽然它具有私有属性和公有字段,但是它不仅仅是一个值对象。它包含用于计算总价和增加数量的业务方法。这种设计使得该业务对象易于理解和重用,即使是在整体设计改进的情况下。当我们介绍持久性方面时,您就会看到该模型的其他部分。 下周,在这个摘录自《Better, Faster, Lighter Java》一书的Spring系列的最后一部分中,作者将讲述如何将持久性添加到Pet Store例子中,并讨论Spring框架中的表示逻辑。 原文出处: Demonstrating Spring's Finesse http://www./pub/a/onjava/excerpt/BFLJava_chap8/index.html
|
|
来自: EverestSnow > 《我的图书馆》