Spring Hibernate 组合的小例子

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 的基础是容器,并且这个基础很重要。但容器远不能代表它的全部。




优势

同我一样,自行车世界冠军 Lance Armstrong 也来自德克萨斯首府奥斯汀。我很多年来,都很喜欢欣赏他的比赛,部分原因在于他从每次登车中得到的优势比世界上任何人得到的都要多。我寻找机会,以从我所做的每件事中得到附加的优势。Spring 通过提供胶水代码,消除麻烦重复的资源管理、配置和应用程序中的繁重工作,使我得到更多的优势。

采用持久性。Hibernate 是一套漂亮的持久性替换方案。但像所有持久性框架一样,它强制您管理一些低级的细节(我宁愿不要它们)。清单 4 展示了一个没有 Spring 的 Hibernate 应用程序示例。



清单 4. 没有 Spring 的 Hibernate
// Configuration code
Configuration config = new Configuration( );
config.addClass(Bike.class).addClass(Customer.class).
addClass(Reservation.class);
SessionFactory mySessionFactory = Configuration.buildSessionFactory( );
 
public List getBikesOldWay( ) throws Exception {
  List bikes = null;
  Session s = null;
  try {
    s = mySessionFactory.openSession( );
    bikes = s.find("from Bike");
  }catch (Exception ex) {
    //handle exception gracefully
  }finally {
    s.close( );
  }
  return bikes;
}

清单 5 展示了一个类似的示例,但它使用了 Spring。



清单 5. 使用 Spring 的 Hibernate
public List getBikes( ) {
  return getHibernateTemplate( ).find("from Bike");
}

可以将 Hibernate 模板看作是实现会话处理的方法。尤其要注意您所没有看到的。您不必担心事务,因为 Spring 让您通过声明配置它们。您也不必担心管理资源,因为代码是在模板中。Spring 总是会关闭会话,所以您不必担心。您不必在这个级别上处理异常,因为 Spring 将它们转换为一套通用的未检查异常(unchecked exceptions)。我喜欢未检查异常,因为我可以选择在架构的合适级别上抛出它们。只需提供很少信息来告诉 Hibernate 做什么。Spring 处理剩下的事情。这就是优势。

Spring 也通过其他途径建立了优势。通过为其他服务提供同种的胶水代码,Spring 减轻了应用程序编程人员的负担。我几乎再也不必像往常一样重复劳动。我可以更加简单地使用远程控制、事务、安全、持久性和 MVC 代码,因为 Spring 确实做到了“减负”。

在这里,我想指出一些不利之处。在我决定使用 Spring 的胶水代码替代自己的胶水代码时,我自己构建了 Spring 框架的依赖关系。通常,我认为付出这种代价非常值得。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值