动态代理实现横切——封装事务

原创 2015年07月27日 22:17:09

    上节课中,通过现象2可知道:如果对各个实现相同的控制,则需要重复写大量的代码。比如说,写日志,事务的开启,关闭,回滚等一系列操作。

    但是在开发的过程中,如果经常注意以上的开发,那开发效率将很低的。而且还容易出错。

    面对上面的问题,如果只是面向对象的编程。那开发的时候,程序员不仅要专注于业务逻辑的Coding,而且还要在后面写上日志的处理办法,事务的开启关闭等一系列与业务逻辑无关的代码。log.write(class,operate)……

效率上肯定是要打折扣的。而且,把这种重复性的工作交给人力。是非常的容易出现问题的。

 

    现在,要想提高效率。重复的工作交给机器。程序员专心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  通过学习的深入,才发现,面向切面的编程是一种思想,不管用什么技术实现。

    面向对象的编程加上面向切面的编程。才会让编程更加有乐趣,更加有效率。

版权声明:本文为博主原创文章,未经博主允许不得转载。

动态代理模式封装事务详解

代理,大家都知道是什么意思。百科上面的解释:以他人的名义,在授权范围内进行对被代理人直接发生法律效力的法律行为。 说白了就是A想交女朋友,但是自己不敢去表白,然后叫B去帮他送花,而B帮助A送了花,B...
  • liu765023051
  • liu765023051
  • 2013年05月31日 10:53
  • 3383

代理模式深入学习(二)——实现动态代理对事务的封装

前两篇博客已经为这篇博客做了很多铺垫,从动态代理的实现衍生原理到threadLocal来封装事务,到最后真正的利用动态代理来封装事务。缺少每一 步都似乎显得有些冒进了!现在剩下的就只是把先前封...
  • wangyy130
  • wangyy130
  • 2015年10月18日 16:37
  • 903

Java事务(五) - 使用动态代理改造

一. 前言: 在上一篇博文中, 我们使用模板模式进行事务管理, 代码看起来已经很简洁了, 但是还是不太完美, 我们依然需要在service层编写和事务相关的代码, 即我们需要在service层宗声明...
  • zdp072
  • zdp072
  • 2014年09月13日 14:02
  • 1234

通过使用反射+动态代理+注解来实现对事务的控制

通过使用反射+动态代理+注解来实现对事务的控制。事务控制的核心:以MVC模式为基础,实现三层架构,分别是servlet层,service层(事务开启的地方),DAO层,当servlet发出一个请求对数...
  • u011058732
  • u011058732
  • 2014年09月20日 15:37
  • 1134

【Java基础】动态代理实现AOP之控制事务

前言在学习设计模式的时候,对静态代理和动态代理做过研究,静态代理倒是很好理解,代码也简单。但是动态代理代码相对复杂,基于当时的水平,没看太懂。这次就来解析一下java中的动态代理。 静态代理缺点静态...
  • u010028869
  • u010028869
  • 2016年01月12日 15:22
  • 1933

特定需求下动态代理导致的Spring事务不能回滚

有一个并没有使用动态生成的代理,而是直接调用的方法本体,也就是内部方法,显而易见,就是child方法。我们总结一下,就是在使用jdk里面的动态代理时,像这种事务内部调用已声明事务的方法是没有用的,这种...
  • u013045878
  • u013045878
  • 2017年02月08日 15:13
  • 747

JDK动态代理给Spring事务埋下的坑

一、场景分析最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下:1、场景A:这...
  • Crystalqy
  • Crystalqy
  • 2018年01月18日 17:25
  • 70

动态代理封装事务

结合上篇博客《动态代理模式》,我们来使用它来封装一下事务管理,记得以前使用事务,对管理的抽象也仅限于抽离出一个类,通过传入数据库连接,对事务进行开启、提交、回滚等操作,每一个。但是仔细想想我们的业务流...
  • lidaasky
  • lidaasky
  • 2013年06月03日 08:09
  • 1796

Java JDK动态代理实现自己的事务管理器

spring aop介绍 spring提供了五种通知类型 Interception Around JointPoint前后调用,实现此类需要实现接口MethodInterceptor。 Befor...
  • qq_23126581
  • qq_23126581
  • 2017年11月06日 11:25
  • 137

jdk动态代理引起的spring事务不起作用

原文地址: https://mp.weixin.qq.com/s/vCZP8sPrtnXWvg6IlcHQOg 一、场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:...
  • lixiaoyi01
  • lixiaoyi01
  • 2018年01月15日 13:34
  • 33
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:动态代理实现横切——封装事务
举报原因:
原因补充:

(最多只允许输入30个字)