结合上篇博客《动态代理模式》,我们来使用它来封装一下事务管理,记得以前使用事务,对管理的抽象也仅限于抽离出一个类,通过传入数据库连接,对事务进行开启、提交、回滚等操作,每一个。但是仔细想想我们的业务流程是固定的,哪里使用或不使用事务也是固定的,所以,事务和业务之间并非必须的耦合关系,以下就是通过动态代理将业务和事务解耦。
代理类
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,所以如果要对原异常进行处理,需要对异常进行类型判断再行处理。
更多DRP系列博客,其访问《DRP项目总结》。