l Spring事务管理
对于数据库事务来说,必须具备ACID特性:
1. 原子性:事务中一系列操作时不可分割的工作单元。要么全部执行,要么全部撤销。
2. 一致性:事务不能破坏数据库中的数据完整性和逻辑上的完整性。
3. 隔离性:多个并发执行的事务操作同一数据出现冲突时,数据库必须协调并保证各事务的独立性。
4. 持久性:事务成功完成后,对数据库状态的更新必须永久地保存下来。
JTA(Java Transaction API)Java事务API,它是JavaEE应用程序的分布式事务标准。一个JTA事务涉及一个事务管理器和多个资源管理器。一个资源管理器可以使任何类型的持久性数据存储系统,包括数据库,MIS和JMS等。事务管理器负责协调所有事物参与者之间的通信。
如果应用程序只使用一个数据库,则使用JDBC就足够了。Spring框架使用同一种抽象的事务编程模型,配合声明式事务管理,则选择JDBC事务还是JTA事务仅仅需要修改配置文件,一般不会涉及代码的改动。
Spring事物模型:Spring将所有的事务管理都抽象为PlatformTransactionManager,TransactionStatus和TransactionDefinition这3个接口,无论其底层关联的具体事务究竟是JDBC事务,JTA事务还是ORM框架自定义的事务。
PlatformTransactionManager:定义了事务管理器,所有与事物相关的操作都由它管理。
TransactionStatus:定义了事务状态,PlatformTransactionManager会跟据TransactionStatus的状态来决定是否回滚事务。
TransactionDefinition:定义了事务的隔离级别和传播行为,在启动事务时,PlatformTransactionManager根据TransactionDefinition来启动合适的事务。
使用Spring的编程式事务管理时,典型的步骤如下:
1. 从Spring容器中获取PlatformTransactionManager实例。
2. 定义TransactionDefinition并设置好事务的隔离级别和传播方式。
3. 通过PlatformTransactionManager.getTransaction()开始一个事务,并获得TransactionStatus对象。
4. 运行需要在事务环境下执行的代码并捕获异常。
5. 如果有异常发生,将TransactionStatus设置为setRollbackOnly(),表示将要回滚事务。
6. 调用PlatformTransactionManager.commit(TransactionStatus)方法提交事务,Spring根据TransactionStatus的状态来决定如何提交事务,如果已经调用了setRollbackOnly(),事务将回滚,如果没有调用setRollbackOnly(),则事务将会被提交。
我们可以应用AOP将事务管理作为一个切面,动态的插入到各个方法的执行前后。实际上,Spring已经替我们做好了该功能,这就是就是Spring提供的声明式事务管理,并且将整个事务配置都放入XML配置文件。步骤如下:
1. 定义DataSource和TransactionManager。
2. 定义目标bean的一个Singleton,并且把DataSource诸如目标bean。
3. 通过TransactionProxyFactoryBean将目标bean封装成具有事务功能的对象。
l Spring的MVC框架
要使用Spring MVC框架,需要以下步骤:
1. 在web.xml中配置DispatcherServlet及URL映射。
2. 编写IoC容器需要的XML配置文件爱你,命名为<servlet-name>-servlet.xml,放到/WEB-INF目录下。
3. 在XML配置文件中定义URL映射方式和使用哪种View技术。
个人觉得,Struts2的MVC框架更易于使用,所以笔者不再详细介绍Spring MVC框架,而是把注意力集中在如何整合其他MVC框架。继承其他框架的关键问题是,如何在第三方MVC框架中访问Spring IoC容器管理的Bean,我们还要保证在第三方MVC框架开始处理用户请求之前,Spring的IoC容器必须初始化完毕。两种方式可以加载Spring的IoC容器。一种是利用第三方框架的扩展点,如Struts的plugin扩展。一种是在web.xml中定义ContextLoaderListener,让Web应用程序一启动就自动加载Spring的IoC容器。定义如下:
<web-app>
…
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
…
</web-app>
默认的, ContextLoaderListener会在/WEB-INF/目录下查找名为applicationContext.xml的文件作为Spring的配置文件加载。如果使用其他文件名,需要预先指定。如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB/INF/cfg1.xml, /WEB/INF/cfg2.xml,</param-value>
</context-param>
l Spring提供的Web服务
为了简化Web服务,Spring提供了LocalJaxRpcServiceFactoryBean和JaxRpcPortProxyFactoryBean来封装一个Web服务的调用。前者只能返回Jax-RPC的服务类,而后者的封装更好,可以返回一个自定义的接口类,是客户端完全和Web服务隔离开。
创建客户端实例:
1) 导入axis的所有jar包,新建一个Eclipse的run,查找到axis中的wsdl2java,键入web服务提供者的uri,从而获取到相关的服务接口和类包。
2) 在Spring的XML配置文件中定义服务提供商的Web服务接口。如下:
<bean id=”amazonWebService” class=”org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean”>
<property name=”serviceInterface” value=”com.amazon.ws.AWSECommerceServicePoryType”/>
<property name=”portInterface” value=”com.amazon.ws.AWSECommerceServicePoryType” />
….
</bean>
3) 通过以上步骤,我们完全可以把Web服务看成是本地Bean并使用它们。
发布Web服务实例:鉴于用axis把本地java转化成WSDL比较麻烦,这里我们使用Xfire发布Web服务。我们以在线书店为例,发布一个书籍查询的功能。
1) 编写一个BookService接口,作为Web服务的接口。
2) 编写一个实现类BookServiceI。
3) 使用JSR 181 Web服务注解来直接标注Web服务BookServiceI。
4) 在Spring的XML配置文件dispatcher-servlet.xml中添加如下内容:
<!--引用Xfire预定义的Bean配置-->
<import resource=”classpath:org/codehaus/xfire/spring/xfire.xml”/>
<!--Web服务实现类-->
<bean id=”bookService” class=”example. BookServiceI”/>
<!—定义URL映射-->
<bean class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”/>
<property name=”urlMap”/>
<map>
<entry key=”/BookService” value=”bookExporter”/>
</map>
</property>
</bean>
<!--bookExporter处理来自客户端的调用-->
<bean id=”bookExporter” class=”org.codehaus.xfire.spring.remoting”>
<!--对外提供的Web服务的接口-->
<property name=”serviceClass” value=”example,BookService”/>
<!--实现Web服务的Bean-->
<property name=”serviceBean” ref=”bookService”/>
<--下面所用的Bean已经被import引入了-->
<property name=”serviceFactory” ref=”xfire. serviceFactory”/>
<property name=”xfire” ref=”xfire”/>
</bean>