现在的位置: 首页 > 综合 > 正文

动态代理封装时事务

2012年06月01日 ⁄ 综合 ⁄ 共 2364字 ⁄ 字号 评论关闭

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

代理类

    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项目总结》。

抱歉!评论已关闭.