首页 > 代码库 > 采用动态代理对事务进行封装

采用动态代理对事务进行封装

         在上篇博客中介绍了使用ThreadLocal维护Connection的方法,这样做的最大的好处就是不用来回的传递Connection了,但是我们有会发现在我们使用事务的时候不可避免的会写许多重复的代码,这些都是与业务逻辑无关的:          

        Connection conn = ConnectionManage.GetConnection();
        ConnectionManage.beginTransaction(conn); 
        ConnectionManage.commitTransaction(conn);//等等代码。
        //以及Catch中的事务回滚,和finally中关闭连接等等

        不仅不合理,而且是重复劳动,程序开发的一个原则就是杜绝重复劳动,做到良好的封装。

        这里,我们就采用动态代理对事务进行封装,使我们的业务逻辑层不再出现有关事务的代码。

package com.hanyi.drp.util;

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 hanyi
 *
 */
public class TransactionHandler implements InvocationHandler {

	private Object targetObject;

	/**
	 * 获取目标类的代理
	 * @param targetObject
	 * @return
	 */
	public Object newProxyInstance(Object targetObject) {
		this.targetObject = targetObject;
		return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
				   targetObject.getClass().getInterfaces(), this);
	}

	/**
	 * 代理方法,调用目标类方法前先调用该方法
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Connection conn = null;
		Object ret = null;
		try {
			// 从ThreadLocal中取得Connection。ConnectionManage是对connection的封装
			conn = ConnectionManage.GetConnection();
			
			//如果是以add,del,modify开头的方法,则手动开启事务
			if (method.getName().startsWith("add")
					|| method.getName().startsWith("del")
					|| method.getName().startsWith("modify")) {
				// 手动控制事务提交
				ConnectionManage.beginTransaction(conn);
			}
			// 调用目标对象的业务逻辑方法
			ret = method.invoke(targetObject, args);
			
			//如果事务为手动提交方式,则手动提交事务
			if (!conn.getAutoCommit()) {
				// 提交事务
				ConnectionManage.commitTransaction(conn);
			}
		} catch (Exception e) {
			//如果事务为手动提交方式,则手动回滚事务
			if (!conn.getAutoCommit()) {
				// 回滚事务
				ConnectionManage.rollbackTransaction(conn);
			}
			e.printStackTrace();
			
			if (e instanceof InvocationTargetException) {
				InvocationTargetException ete = (InvocationTargetException) e;
				throw ete.getTargetException();
			}
			
			throw new Exception("操作失败!");
		} finally {
			//关闭连接
			ConnectionManage.closeConnection();
		}
		return ret;

	}

}

原理:当我们在工厂中获取业务逻辑层对象的时候,我们获取的并不是目标对象,而是目标对象的代理,代理替我们管理事务的开启,提交,回滚,与关闭

 

在工厂中用动态代理包装业务逻辑对象

public synchronized Object GetServiceBean(Class c) {  
        if (ServiceMap.containsKey(c.getName())) {  
            return ServiceMap.get(c.getName());  
        }  
  
        Element beanEle = (Element) doc.selectSingleNode("//Service[@id=\""  
                + c.getName() + "\"]");  
        String className = beanEle.attributeValue("class");  
        // System.out.print(className);  
        Object serviceBean = null;  
        try {  
            serviceBean = Class.forName(className).newInstance();  
              
            //采用动态代理包装Service  
            TransactionHandler transactionHandler = new TransactionHandler();  
            //得到代理  
            serviceBean = transactionHandler.newProxyInstance(serviceBean);  
              
            ServiceMap.put(c.getName(), serviceBean);  
        } catch (Exception e) {  
            throw new RuntimeException();  
        }  
        return serviceBean;  
  
    }  
在具体的使用过程中,获取的并不是目标对象,而是目标对象的代理。

userManager = (UserManager) getBeanFactory().GetServiceBean(UserManager.class); 


采用动态代理对事务进行封装