Spring AOP
软件系统通常由多个组件构成每个组件负责一个特定的功能领域但是这些组件也经常承担它们的核心功能之外的额外责任系统服务(例如日志事务管理和安全性)经常发现自己跑到了别的组件的领域里而这些组件的核心职责是其他事情结果就是所谓的代码纠缠或者更简单点儿说一团糟面向方面编程是一种试图解决这个问题的编程技术它把关注点的隔离提升为核心的编程概念
使用 AOP 时仍然是在一个地方定义系统的公共功能但是可以声明性地定义 如何 和 在哪里 应用这个功能如果对横切关注点(例如日志和事务管理)进行了模块化那么不用修改每个单独的类就可以向代码中添加新特性这类模块化的关注点称作 方面
您知道么?
可以在任何 Java? 企业版(JEE) 服务器中使用 Spring 框架的功能而且还可以调整它的大多数功能使其适合不受控环境Spring 的中心焦点就是支持不被束缚在特定 JEEE 服务上的可重用业务和数据访问对象可以跨 JEE 环境(Web 或企业 JavaBean(EJB))独立应用程序测试环境等等重用这类对象而不会有任何麻烦
以一个企业应用程序为例这类应用程序通常要求类似于安全性和事务支持的服务显然可以把这些服务的支持直接编写到要求服务的每个类当中但是更希望能够不必为大量事务性上下文编写同样的事务处理代码如果使用 Spring AOP 进行事务处理那么可以声明性地安排适当的方法调用而不必逐个安排
Spring AOP 提供了几个方面可以为 JavaBean 声明事务例如TransactionProxyFactoryBean 是个方便的代理类能够拦截对现有类的方法调用并把事务上下文应用到事务 bean在下面的示例中会看到这个类的实际应用
Hibernate
Spring 框架提供了对 HibernateJDO 和 iBATIS SQL Maps 的集成支持Spring 对 Hibernate 的支持是第一级的整合了许多 IOC 的方便特性解决了许多典型的 Hibernate 集成问题框架对 Hibernate 的支持符合 Spring 通用的事务和数据访问对象(DAO)异常层次结构
Spring 为使用选择的 OR 映射层来创建数据访问应用程序提供了支持因为所有东西都设计成一组可重用 JavaBean所以不管选择什么技术都能以库的格式访问大多数 Spring 的 OR 映射支持 ApplicationContext 或 BeanFactory 内部的 OR 映射的好处是简化了配置和部署
Hibernate 是 Java 平台上一个功能全面的开源的 OR 映射框架Hibernate 支持开发符合常规 Java 理念的持久性类 —— 包括关联继承多态复合以及 Java 集合框架Hibernate 查询语言(HQL)被设计成 SQL 的一个微型面向对象扩展它是对象和关系世界之间的桥梁Hibernate 也支持用原始 SQL 或基于 Java 的标准和示例查询表达查询Hibernate 使用 XML(*hbmxml) 文件把 Java 类映射到表把 JavaBean 属性映射到数据库表
通过 JDBC 技术支持所有的 SQL 数据库管理系统Hibernate 与所有流行的 JEE 应用程序服务器和 Web 容器都很好地集成
实际示例
一个银行应用程序示例可以让您自己看到 Spring AOP 和 Hibernate 一起工作有多么好银行帐户用例允许用户 (Customer) 在一个事务中打开一个或多个银行帐户用户可以申请多个银行帐户可以选择是支票帐户类型或者是储蓄帐户类型
应用程序数据库(Cloudscape?)容纳所有客户和帐户信息在这个例子中假设在 Customer 和 Account 类之间存在 :N 的关联在实际生活场景中关联可能需要按 m:n 建模才能支持联合帐户
由于用户必须可以在一个事务中申请多个帐户所以首先要为数据库交互实现一个 DOA 模式然后要设置 Spring AOP 的 TransactionProxyFactoryBean让它拦截方法调用并声明性地把事务上下文应用到 DOA
Hibernate 实践
在 Spring 框架中像 JDBC DataSource 或 Hibernate SessionFactory 这样的资源在应用程序上下文中可以用 bean 实现需要访问资源的应用程序对象只需通过 bean 引用得到这类预先定义好的实例的引用即可(这方面的更多内容在 下一节中)在清单 中可以看到示例银行应用程序的一段摘录XML 应用程序上下文定义显示了如何设置 JDBC DataSource并在上面放一个 Hibernate SessionFactory
清单 JDBC DataSource 和 HibernateSessionFactory 连接
<! DataSource Property >
<bean id=exampleDataSource
class=monsdbcpBasicDataSource>
<property name=driverClassName>
<value>orgapachederbyjdbcEmbeddedDriver</value>
</property>
<property name=url>
<value>jdbc:derby:springexample;create=true</value>
</property>
</bean>
<! Database Property >
<bean id=exampleHibernateProperties
class=orgspringframewonfigPropertiesFactoryBean>
<property name=properties>
<props>
<prop key=hibernatehbmddlauto>update</prop>
<prop
key=hibernatedialect>netsfhibernatedialectDerbyDialect</prop>
<prop
key=hibernatequerysubstitutions>true T false F</prop>
<prop key=hibernateshow_sql>false</prop>
<prop key=hibernatecpminPoolSize></prop>
<prop key=hibernatecpmaxPoolSize></prop>
<prop key=hibernatecptimeout></prop>
<prop key=hibernatecpmax_statement></prop>
<prop
key=hibernatecptestConnectionOnCheckout>false</prop>
</props>
</property>
</bean>
<! Hibernate SessionFactory >
<bean id=exampleSessionFactory
class=orgspringframeworkormhibernateLocalSessionFactoryBean>
<property name=dataSource>
<ref local=exampleDataSource/>
</property>
<property name=hibernateProperties>
<ref bean=exampleHibernateProperties />
</property>
<!OR mapping files >
<property name=mappingResources>
<list>
<value>Customerhbmxml</value>
<value>Accounthbmxml</value>
</list>
</property>
</bean>
清单 显示了如何为示例应用程序数据库(是 Cloudscape)配置数据源 bean (exampleDataSource)exampleDatasource 被连接到 Spring Hibernate 的 SessionFactory请注意 *hbmxml 指定了示例应用程序的 OR 映射文件
数据源和会话工厂设置好之后下一步就是在 DAO 中连接在 CustomerDAOImpl 示例中要使用 SessionFactory接下来插入 Spring 的 TransactionProxyFactoryBean它会拦截对应用程序的 CustomerDAOImpl 对象的方法调用并声明性地在它上面应用事务
在 清单 的这个示例中CustomerDAOImpl 类的 addCustomer 方法是作为事务的一部分执行的有一个事务属性 PROPAGATION_REQUIRED这个属性等价于 EJB 容器的 TX_REQUIRED如果想让这个方法一直在事务中运行可以使用 PROPAGATION_REQUIRED如果事务已经在运行那么 bean 方法会加入事务否则 Spring 的轻量级事务管理器会启动一个事务如果想在调用组件服务时总是启动新事务可以使用 PROPAGATION_REQUIRES_NEW 属性
应用程序的连接完成之后现在来进一步查看源代码
分析这个!
如果以前没这么做过那么请 下载这篇文章的源代码把源 zip 文件释放到计算机中的任何位置上例如 c:\会创建一个叫作 SpringProjectPart 的文件夹src\spring 文件夹包含示例应用程序的 Hibernate 映射文件和 Spring 配置文件src\springexample\hibernate 文件包含应用程序的源代码
在这里会发现两个类即 Customer 和 Account它们用 Hibernate 映射文件映射到两个表Customer 类代表客户信息Account 代表客户的帐户信息正如前面提到的我把这两个类按照 : N 关系进行建模即一个 Customer 可以拥有多个 Account清单 显示了 Customer 对象的 Hibernate 映射文件
清单 Customer 对象的 Hibernate 映射文件
<?xml version=?>
<!DOCTYPE hibernatemapping PUBLIC
//Hibernate/Hibernate Mapping DTD //EN
mappingdtd>
<hibernatemapping>
<class
name=springexamplehibernateCustomer
table=TBL_CUSTOMER
dynamicupdate=false
dynamicinsert=false>
<id
name=id
column=CUSTOMER_ID
type=javalangLong
unsavedvalue=
>
<generator class=native>
</generator>
</id>