曹學成 廊坊師範學院資訊科技提高班 十四期
阿新 • • 發佈:2018-12-19
由於dao的設計粒度比manager要細,所以一個manager會呼叫多個dao的方法,這些方法要麼要執行成功,要麼都不執行。這時候就要引入事務。如下圖:
但是類那麼多,每個寫這幾句話不僅很麻煩,而且還不好去管理。這時就引入了動態的代理模式來封裝這些程式碼。
1、首先建立一個代理類實InvocationHandler介面。
2、定義目標物件,在newProxyInstance方法中傳入目標物件,並呼叫
Proxy的newProxyInstance方法。該方法有三個引數
(1)目標物件類載入器
(2)目標物件的介面
(3)把代理類傳進去
3、重寫invoke方法。
如下圖:
public class TransactionHandler implements InvocationHandler { private Object targetObject; public Object newProxyInstance(Object tarObject) { this.targetObject=tarObject; return Proxy.newProxyInstance(tarObject.getClass().getClassLoader(), tarObject.getClass().getInterfaces() , this); } @Override 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()==false){ ConnectionManager.commitTransaction(conn); } }catch(ApplicationException e){ ConnectionManager.rollbackTransaction(conn); throw e; } catch(Exception e){ if(e instanceof InvocationTargetException){ InvocationTargetException ete=(InvocationTargetException)e; throw ete.getTargetException(); } e.printStackTrace(); ConnectionManager.rollbackTransaction(conn); throw new ApplicationException("操作失敗"); }finally{ ConnectionManager.closeConnection(); } return ret; } }
代理類寫好以後,在上幾篇部落格中曾說過把service(就是manager)放入工廠中實現。那麼現在在工廠中把生成好的service用代理包裝,就可以相當於service的代理類。
try { service= Class.forName(className).newInstance(); //採用動態代理包裝service TransactionHandler transactionHandler=new TransactionHandler(); service= transactionHandler.newProxyInstance(service); //將建立的物件放入map中 serviceMap.put(s.getName(), service); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(); } return service;
以後manager類就只用關係業務邏輯了,也不用關係conn等的資源有沒有釋放等問題,程式碼就簡潔了。
try{
//生成流向單單號
String flowCardVouNo=flowCardDao.generateVouNo();
//新增流向單主資訊
flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard);
//新增流向單明細資訊
flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList());
}catch(DaoException e){
throw new ApplicationException("新增流向單失敗");
}