import javalangreflectInvocationHandler;
import javalangreflectMethod;
import javalangreflectProxy;
import javasqlConnection;
import comstrutsletdemoserviceSystemException;
public final class TransactionWrapper {
/**
* 装饰原始的业务代表对象返回一个与业务代表对象有相同接口的代理对象
*/
public static Object decorate(Object delegate) {
return ProxynewProxyInstance(delegategetClass()getClassLoader()
delegategetClass()getInterfaces() new XAWrapperHandler(
delegate));
}
//动态代理技术
static final class XAWrapperHandler implements InvocationHandler {
private final Object delegate;
XAWrapperHandler(Object delegate) {
thisdelegate = delegate;
}
//简单起见包装业务代表对象所有的业务方法
public Object invoke(Object proxy Method method Object[] args)
throws Throwable {
Object result = null;
Connection con = ConnectionManagergetConnection();
try {
//开始一个事务
consetAutoCommit(false);
//调用原始业务对象的业务方法
result = methodinvoke(delegate args);
concommit(); //提交事务
consetAutoCommit(true);
} catch (Throwable t) {
//回滚
conrollback();
consetAutoCommit(true);
throw new SystemException(t);
}
return result;
}
}
}
正如我们所见此对象只不过把业务对象需要事务控制的业务方法中的事务控制部分抽取出来而已请注意业务代表对象内部调用自身的方法将不会开始新的事务因为这些调用不会传给代理对象如此我们去除了代表重复的味道此时我们的业务代表对象修改成
public class BookStoreManagerImpl implements BookStoreManager {
public boolean buyBook(String bookId)throws SystemException{
Connection conn=ConnectionManagergetConnection();// 获取数据库连接
boolean b=false;
try{
BookDAO bookDAO=DAOFactorygetBookDAO();
CustomerDAO customerDAO=DAOFactorygetCustomerDAO();
// 尝试从库存中取书
if(BookDAOreduceInventory(connbookIdquantity)){
BigDecimal price=BookDAOgetPrice(bookId); // 取价格
// 从客户帐户中扣除price*quantity的费用
b=
CustomerDAOreduceAccount(connpricemultiply(new BigDecimal(quantity));
其他业务方法如通知管理员生成定单等
}
}catch(SQLException e){
throws new SystemException(e);
}
return b;
}
}
可以看到此时的业务代表对象专注于实现业务逻辑它不再关心事务控制细节把它们全部委托给了外部对象业务代表工厂也修改一下让它返回两种类型的业务代表对象
public final class ManagerFactory {
//返回一个被包装的对象有事务控制能力
public static BookStoreManager getBookStoreManagerTrans() {
return (BookStoreManager) TransactionWrapper
decorate(new BookStoreManagerImpl());
}
//原始版本
public static BookStoreManager getBookStoreManager() {
return new BookStoreManagerImpl();
}
}
我们在业务代表工厂上提供了两种不同的对象生成方法一个用于创建被包装的对象它会为每次方法调用创建一个新的事务另外一个用于创建未被包装的版本它用于加入到已有的事务(比如其他业务代表对象的业务方法)解决了嵌套业务代表对象的问题
我们的设计还不够优雅比如我们默认所有的业务代表对象的方法调用都将被包装在一个Transaction Context可事实是很多方法也许并不需要与数据库打交道如果我们能配置哪些方法需要事务声明哪些不需要事务管理就更完美了解决办法也很简单一个XML配置文件来配置这些调用时判断即可说到这里了解spring的大概都会意识到这不正是声明式事务控制吗?正是如此事务控制就是AOP的一种服务spring的声明式事务管理是通过AOP实现的AOP的实现方式包括动态代理技术字节码生成技术(如CGLIB库)java代码生成(早期EJB采用)修改类装载器以及源代码级别的代码混合织入(aspectj)等我们这里就是利用了动态代理技术只能对接口代理对类的动态代理可以使用cglib库
这篇短文只是介绍下我对事务上下文模式以及声明式事务管理实现基本原理的理解如有错误请不吝赐教谢谢我的email:killme@gmailcom
[] []