前两篇博客已经为这篇博客做了很多铺垫,从动态代理的实现衍生原理到threadLocal来封装事务,到最后真正的利用动态代理来封装事务。缺少每一
步都似乎显得有些冒进了!现在剩下的就只是把先前封装好的事务加进到写好的动态代理类中就好了!
动态代理与事务结合
package com.bjpowernode.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 yanyan
*
*/
public class TransactionHandler implements InvocationHandler {
private Object targetObject;
/**
* 将要代理的类传递给该类,同时在该类中保存这个类的对象
* @param targetObject
* @return
*/
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
/**
* 1/targetObject:要代理的类的对象
* 2/代理的类所实现的接口,便于生成的代理类去实现这个接口
* 3/每个生成的代理类要回调一个实现了InvocationHandler的内部函数,这个函数放在这个类里面就是invoke函数,为了适应多种类,要写活
*/
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;
}
}
将动态代理封装的事务嵌进原始调用对象中
package com.bjpowernode.drp.util;
import java.util.HashMap;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.bjpowernode.drp.flowcard.manager.FlowCardManager;
/**
* 抽象工厂,主要创建两个系列的产品
* 1、manager系列
* 2、dao系列
* @author yanyan
*
*/
public class BeanFactory {
private final String beansConfigFile="beans-config.xml";
private Document doc;
private static BeanFactory instance=new BeanFactory();
private Map serviceMap=new HashMap();
private Map daoMap=new HashMap();
private BeanFactory(){
//装载配置文件
try {
doc=new SAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException();
}
}
public static BeanFactory getInstance(){
return instance;
}
/**
* 根据产品编号取得service系列产品
* @param beanId
* @return
*/
public synchronized Object getServiceObject(Class c){
//首先判断是否存在该对象
if(serviceMap.containsKey(c.getName())){
return serviceMap.get(c.getName());
}
//如果不存在,则创建一个
// //代表以bean路径结尾的所有元素,用“//” 表示所有路径以"//"后指定的子路径结尾的元素
Element beanElt=(Element) doc.selectSingleNode("//service[@id=\""+c.getName()+"\"]");
/*String className=beanElt.getTextTrim();*/
String className=beanElt.attributeValue("class");
Object service=null;
try {
service=Class.forName(className).newInstance();
TransactionHandler transactionHandler=new TransactionHandler();
service=transactionHandler.newProxyInstance(service);
//将创建好的对象放到map中
serviceMap.put(c.getName(), service);
} catch (Exception e) {
throw new RuntimeException(e);
}
return service;
}
/**
* 根据产品编号取得dao系列产品
* @param beanId
* @return
*/
public synchronized Object getDaoObject(Class c){
//首先判断是否存在该对象
if(daoMap.containsKey(c.getName())){
return daoMap.get(c.getName());
}
//如果不存在,则创建一个
// //代表以bean路径结尾的所有元素,用“//” 表示所有路径以"//"后指定的子路径结尾的元素
Element beanElt=(Element) doc.selectSingleNode("//dao[@id=\""+c.getName()+"\"]");
/*String className=beanElt.getTextTrim();*/
String className=beanElt.attributeValue("class");
Object dao=null;
try {
dao=Class.forName(className).newInstance();
TransactionHandler transactionHandler=new TransactionHandler();
dao=transactionHandler.newProxyInstance(dao);
//将创建好的对象放到map中
daoMap.put(c.getName(), dao);
} catch (Exception e) {
throw new RuntimeException("创建失败");
}
return dao;
}
}
调用
private FlowCardDao flowCardDao;
//这里通过构造函数调用的beanFactory实现代码中已经启用了动态代理封装的事务
this.flowCardDao=(FlowCardDao)BeanFactory.getInstance().getDaoObject(FlowCardDao.class);
}
public void addFlowCard(FlowCard flowCard) throws ApplicationException {
//Connection conn=null;
try{
//conn=ConnectionManager.getConnection();
//开始事务
//ConnectionManager.beginTransaction(conn);
//生成流向单单号
String flowCardVouNo=flowCardDao.generateVouNo();
//添加流向单主信息
flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard);
//添加明细信息
flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList());
//提交事务
//ConnectionManager.commitTransaction(conn);
}catch(DaoException e){
//回滚事务
//ConnectionManager.rollbackTransaction(conn);
throw new ApplicationException(e);
}/*finally{
ConnectionManager.closeConnection();
}
*/
}
从注释的代码中可以看到,我们利用动态代理封装的事务可以大大减少代码的重复。
提示:如果从以上代码中未能明白为什么调用了事务,建议翻看前面的两篇博客,其实在构造函数中调用的beanFactory中的getDaoObject方法时实现时,就已经调用了动态代理来实现,所以,从始至终其实,在真正的实现类中一直是代理类在执行的!
博客参考:
代理模式深入学习一
theadLocal封装事务