结合上篇博客《动态代理模式》,我们来使用它来封装一下事务管理,记得以前使用事务,对管理的抽象也仅限于抽离出一个类,通过传入数据库连接,对事务进行开启、提交、回滚等操作,每一个。但是仔细想想我们的业务流程是固定的,哪里使用或不使用事务也是固定的,所以,事务和业务之间并非必须的耦合关系,以下就是通过动态代理将业务和事务解耦。
代理类
TransactionHandler,这个是对事务操作的核心,将需要事务的函数在此处理:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
/**
* 采用动态代理封装事务
* @author Administrator
*
*/
public class TransactionHandler implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Connection conn = null;
Object ret = null;
try {
//从ThreadLocal中取得Connection
conn = ConnectionManager.getConnection();
if (method.getName().startsWith("add") ||
method.getName().startsWith("del") ||
method.getName().startsWith("modify")) {
//手动控制事务提交
ConnectionManager.beginTransaction(conn);
}
//调用目标对象的业务逻辑方法
ret = method.invoke(targetObject, args);
if (!conn.getAutoCommit()) {
//提交事务
ConnectionManager.commitTransaction(conn);
}
}catch(ApplicationException e) {
//回滚事务
ConnectionManager.rollbackTransaction(conn);
throw e;
}catch(Exception e) {
e.printStackTrace();
if (e instanceof InvocationTargetException) {
InvocationTargetException ete = (InvocationTargetException)e;
throw ete.getTargetException();
}
//回滚事务
ConnectionManager.rollbackTransaction(conn);
throw new ApplicationException("操作失败!");
}finally {
ConnectionManager.closeConnection();
}
return ret;
}
}
使用封装的事务
在工厂中创建Service实例时,使用封装的事务。
/**
* 根据产品编号取得Service系列产品
* @param beanId
* @return
*/
public synchronized Object getServiceObject(Class c){
//如果存在相关对象实例,返回
if (serviceMap.containsKey(c.getName())) {
return serviceMap.get(c.getName());
}
Element beanElt = (Element)doc.selectSingleNode("//service[@id=\"" + c.getName() + "\"]");
String className = beanElt.attributeValue("class");
Object service = null;
try {
service = Class.forName(className).newInstance();
//采用动态代理包装Service
TransactionHandler transactionHandler = new TransactionHandler();
service = transactionHandler.newProxyInstance(service);
//将创建好的对象放到Map中
serviceMap.put(c.getName(), service);
} catch (Exception e) {
throw new RuntimeException();
}
return service;
}
在这里我们需要注意的是,当代理类截获异常后,会对异常进行封装,封装为InvocationTargetException,所以如果要对原异常进行处理,需要对异常进行类型判断再行处理。
更多博客,其访问《项目总结》。