首页 > 代码库 > 动态代理实现横切——封装事务
动态代理实现横切——封装事务
上节课中,通过现象2可知道:假设对各个实现同样的控制。则须要反复写大量的代码。比方说,写日志,事务的开启。关闭,回滚等一系列操作。
可是在开发的过程中,假设常常注意以上的开发,那开发效率将非常低的。并且还easy出错。
面对上面的问题。假设仅仅是面向对象的编程。那开发的时候。程序猿不仅要专注于业务逻辑的Coding,并且还要在后面写上日志的处理办法,事务的开启关闭等一系列与业务逻辑无关的代码。
log.write(class,operate)……
效率上肯定是要打折扣的。并且,把这样的反复性的工作交给人力。是很的easy出现故障的。
如今。要想提高效率。反复的工作交给机器。程序猿专心Coding业务逻辑。
面向切面的编程,能够解决这样的问题。
前提:事务的控制。发生在B层,dal层是对数据的訪问。
而业务逻辑的整合在B层。所以须要对B层中的方法,都加上事务。
取得B层实现。是通过工厂取得。
用动态代理封装事务:
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; /** * 採用动态代理封装事务 */ 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 (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; } }
通过上面的方法,能够对B层的对象 进行一个包装的过程,使得对 add 、del、modify开头的方法。包装上一层事务的 开启 提交 回滚等一系列操作。
获取B层实现的方法:
/** * 依据产品编号取得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"); // System.out.println(className); 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) { e.printStackTrace(); throw new RuntimeException("创建Service失败!"); } return service; }
在获取B层对象实例的时候, 进行包装事务。
通过上面getServiceObject获取得到的B层对象。在调用增删改操作的时候,都会有事务控制。这样程序猿在开发的过程中就能够专心的开发业务逻辑。而不用思考什时候须要开启事务,什么情况须要提交,什么时候须要回滚等一系列与业务逻辑无关的操作。
在此之前。一直以为实现面向切面的编程须要使用Spring.AOP 通过学习的深入,才发现,面向切面的编程是一种思想。无论用什么技术实现。
面向对象的编程加上面向切面的编程。才会让编程更加有乐趣,更加有效率。
动态代理实现横切——封装事务