1. 程式人生 > >曹學成 廊坊師範學院資訊科技提高班 十四期

曹學成 廊坊師範學院資訊科技提高班 十四期

由於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("新增流向單失敗");
	                }