动态代理封装时事务

结合上篇博客《动态代理模式》,我们来使用它来封装一下事务管理,记得以前使用事务,对管理的抽象也仅限于抽离出一个类,通过传入数据库连接,对事务进行开启、提交、回滚等操作,每一个。但是仔细想想我们的业务流程是固定的,哪里使用或不使用事务也是固定的,所以,事务和业务之间并非必须的耦合关系,以下就是通过动态代理将业务和事务解耦。

代理类

TransactionHandler,这个是对事务操作的核心,将需要事务的函数在此处理:

[java] view plaincopyprint?

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.InvocationTargetException;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.sql.Connection;
  6. /**
  7.  * 采用动态代理封装事务
  8.  * @author Administrator
  9.  *
  10.  */
  11. public class TransactionHandler implements InvocationHandler {
  12.     private Object targetObject;
  13.     public Object newProxyInstance(Object targetObject) {
  14.         this.targetObject = targetObject;
  15.         return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
  16.                                targetObject.getClass().getInterfaces(), this);
  17.     }
  18.     public Object invoke(Object proxy, Method method, Object[] args)
  19.             throws Throwable {
  20.         Connection conn = null;
  21.         Object ret = null;
  22.         try {
  23.             //从ThreadLocal中取得Connection
  24.             conn = ConnectionManager.getConnection();
  25.             if (method.getName().startsWith(“add”) ||
  26.                 method.getName().startsWith(“del”) ||
  27.                 method.getName().startsWith(“modify”)) {
  28.                 //手动控制事务提交
  29.                 ConnectionManager.beginTransaction(conn);
  30.             }
  31.             //调用目标对象的业务逻辑方法
  32.             ret = method.invoke(targetObject, args);
  33.             if (!conn.getAutoCommit()) {
  34.                 //提交事务
  35.                 ConnectionManager.commitTransaction(conn);
  36.             }
  37.         }catch(ApplicationException e) {
  38.             //回滚事务
  39.             ConnectionManager.rollbackTransaction(conn);
  40.             throw e;
  41.         }catch(Exception e) {
  42.             e.printStackTrace();
  43.             if (e instanceof InvocationTargetException) {
  44.                 InvocationTargetException ete = (InvocationTargetException)e;
  45.                 throw ete.getTargetException();
  46.             }
  47.             //回滚事务
  48.             ConnectionManager.rollbackTransaction(conn);
  49.             throw new ApplicationException(“操作失败!”);
  50.         }finally {
  51.             ConnectionManager.closeConnection();
  52.         }
  53.         return ret;
  54.     }
  55. }

 

 

使用封装的事务

在工厂中创建Service实例时,使用封装的事务。

 

[java] view plaincopyprint?

  1. /**
  2.  * 根据产品编号取得Service系列产品
  3.  * @param beanId
  4.  * @return
  5.  */
  6. public synchronized Object getServiceObject(Class c){
  7.     //如果存在相关对象实例,返回
  8.     if (serviceMap.containsKey(c.getName())) {
  9.         return serviceMap.get(c.getName());
  10.     }
  11.     Element beanElt = (Element)doc.selectSingleNode(“//service[@id=\”” + c.getName() + “\”]”);
  12.     String className = beanElt.attributeValue(“class”);
  13.     Object service = null;
  14.     try {
  15.         service = Class.forName(className).newInstance();
  16.         //采用动态代理包装Service
  17.         TransactionHandler transactionHandler = new TransactionHandler();
  18.         service = transactionHandler.newProxyInstance(service);
  19.         //将创建好的对象放到Map中
  20.         serviceMap.put(c.getName(), service);
  21.     } catch (Exception e) {
  22.         throw new RuntimeException();
  23.     }
  24.     return service;
  25. }

在这里我们需要注意的是,当代理类截获异常后,会对异常进行封装,封装为InvocationTargetException,所以如果要对原异常进行处理,需要对异常进行类型判断再行处理。

标签