深入剖析动态代理(上)之代理的方式

关于动态代理,大家显式使用的可能比較少,可是说到Spring的Interceptor、各种各样的事务管理,大家会更熟悉一些,没错,这些在底层实现上,都是使用的动态代理,确切的说,想要为一个类的方法,动态加入功能,比方验证、资源释放、日志处理等,大部分都是借助动态代理。

为了平缓的过渡,先来说一下静态代理。

静态代理

静态代理的思路非常easy:把一个真实对象的实例放到代理对象的实例中。然后调用代理对象方法,代理对象的方法调用真实对象的方法,以事务管理为例。例如以下:

UserDao

package com.tgb.staticproxy;

public interface UserDao {

	public void add();
	public void deleteAll();
}

UserDaoImpl

package com.tgb.staticproxy;

public class UserDaoImpl implements UserDao {

	public void add()
	{
		System.out.println("加入一名用户到数据库");
	}
	public void deleteAll()
	{
		System.out.println("删除全部用户");
	}
}

UserDaoProxy

package com.tgb.staticproxy;

public class UserDaoProxy implements UserDao {

	UserDao userDao=null;
	public UserDaoProxy(UserDao userDao)
	{
		this.userDao=userDao;
	}

	public void add()
	{
		System.out.println("开启本地事务");
		userDao.add();
		System.out.println("提交或回滚事务");
	}
	public void deleteAll()
	{
		System.out.println("开启本地事务");
		userDao.deleteAll();
		System.out.println("提交或回滚事务");
	}
}

Test

package com.tgb.staticproxy;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		UserDao userDao=new UserDaoImpl();
		UserDaoProxy userDaoProxy=new UserDaoProxy(userDao);

		//測试加入
		userDaoProxy.add();
		System.out.println("..........分隔符..........");
		//測试删除
		userDaoProxy.deleteAll();

	}

}

运行结果

开启本地事务
加入一名用户到数据库
提交或回滚事务
..........分隔符..........
开启本地事务
删除全部用户
提交或回滚事务

可是静态代理管理事务的方式问题非常大,每一个Dao类的每一个方法都须要开启和关闭事务,不仅代码反复严重,而事务本来是和业务没什么关联,却耦合到一起。

动态代理

JDK动态代理

相同以事务管理为例,例如以下:

UserDao

package com.tgb.dynamicproxy;

public interface UserDao {

	public void add();
	public void deleteAll();
}

UserDaoImpl

package com.tgb.dynamicproxy;

public class UserDaoImpl implements UserDao {

	@Override
	public void deleteAll() {
		System.out.println("删除全部用户信息");
	}
	@Override
	public void add() {
		System.out.println("加入一名用户到数据库");
	}

}

Handler

package com.tgb.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Handler implements InvocationHandler {

	private Object target;

	public Handler(Object target)
	{
		this.target=target;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//开启事务
		before();
		//运行业务
		method.invoke(target, args);
		//提交或回滚事务
		after();

		return null;
	}
	public void before()
	{
		System.out.println("開始本地事务");
	}
	public void after()
	{
		System.out.println("提交或回滚事务");
	}
}

Test

package com.tgb.dynamicproxy;

import java.lang.reflect.Proxy;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try{
			UserDao impl=new UserDaoImpl();
			Handler handler=new Handler(impl);
			UserDao proxy=(UserDao)Proxy.newProxyInstance
				(impl.getClass().getClassLoader(), impl.getClass().getInterfaces(), handler);

			//測试加入
			proxy.add();
			System.out.println("..........分隔符..........");
			//測试删除
			proxy.deleteAll();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

	}

}

运行结果

開始本地事务
加入一名用户到数据库
提交或回滚事务
..........分隔符..........
開始本地事务
删除全部用户信息
提交或回滚事务

JDK的动态代理克服了静态代理耦合和代码反复的问题,可是JDK的代理模式有个比較严重的问题。如UserDao必需要有接口才干够使用JDK动态代理,这就大大限制了JDK动态代理的范围。

cglib动态代理

asm能够动态生成字节码,cglib对asm进行了再封装,cglib并非为了动态代理而生的,可是利用它的特性。却能够非常好的实现动态代理。

UserDaoImpl

package com.tgb.cglib;

public class UserDaoImpl  {

	public void deleteAll() {
		System.out.println("删除全部用户信息");
	}

	public void add() {
		System.out.println("加入一名用户到数据库");
	}

}

CglibProxy

package com.tgb.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor  {

	private Object target;
    private CglibProxy(Object target){
       this.target = target;
    }
    //产生代理对象
    @SuppressWarnings("unchecked")
	public static <T> T proxyTarget(T t){

       Enhancer en = new Enhancer();
       en.setSuperclass(t.getClass());
       en.setCallback((Callback) new CglibProxy(t));
       T tt = (T) en.create();
       return tt;

    }

    //运行拦截
    public Object intercept(Object obj, Method method, Object[] args,
           MethodProxy proxy) throws Throwable {

       System.out.println("开启本地事务");
       Object o = method.invoke(target, args);
       System.out.println("提交或回滚事务");
       return o;
    }
}

Test

package com.tgb.cglib;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//获代替理对象
		UserDaoImpl impl=CglibProxy.proxyTarget(new UserDaoImpl());
		//測试加入
		impl.add();
		System.out.println("..........分隔符..........");
		//測试删除
		impl.deleteAll();
	}

}

执行结果

开启本地事务
加入一名用户到数据库
提交或回滚事务
..........分隔符..........
开启本地事务
删除全部用户信息
提交或回滚事务

能够看到,这次UserDaoImpl并没有实现不论什么接口接口实现动态代理的功能。

总结

这篇博客本来打算写JDK和cglib动态代理的源代码介绍的。写着写着就写成介绍代理都有哪些类型及实现方式了,再写篇幅就有点长了。所以放到下篇博客说明。

时间: 2024-10-18 21:07:05

深入剖析动态代理(上)之代理的方式的相关文章

Java反射机制剖析(四)-深度剖析动态代理原理及总结

动态代理类原理(示例代码参见java反射机制剖析(三)) a)  理解上面的动态代理示例流程 a)  理解上面的动态代理示例流程 b)  代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Proxy0)的源代码和整个动态代理的流程. $Proxy0生成的代码如下: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; impo

深入剖析动态代理

动态代理是指在运行时,动态生成代理类.代理类的字节码将在运行时生成并载入当前的ClassLoader. 生成动态代理类的方法很多,如JDK自带的动态代理.CGLIB.Javassist或者ASM库. JDK动态代理使用简单,它内置在JDK中,因此不需要引入第三方Jar包,但相对功能比较弱.CGLIB和Javassist都是高级的字节码生成库,总体性能比JDK自带的动态代理好,而且功能十分强大.ASM是低级的字节码生成工具,使用ASM已经近乎在于使用Javabytecode编程,对开发人员要求较高

设计模式-深入剖析动态代理模式(3)内部运作机制-通俗代码版

public interface Subject { //业务操作 public void doSomething(String abc); } ----- public class RealSubject implements Subject { //业务操作 public void doSomething(String str) { System.out.println("do something!---->" + str); } } ---- public class My

Spring框架_代理模式(静态代理,动态代理,cglib代理)

共性问题: 1. 服务器启动报错,什么原因? * jar包缺少.jar包冲突 1) 先检查项目中是否缺少jar包引用 2) 服务器: 检查jar包有没有发布到服务器下:                                      用户库jar包,需要手动发布到tomcat. (每次新建项目) 3) 重新发布项目 * 配置文件错误 (web.xml / struts.xml /bean.xml /hibernate.xml / *.hbm.xml) 明确的提示 * 端口占用 * we

Atitit 代理CGLIB&#160;动态代理&#160;AspectJ静态代理区别

Atitit 代理CGLIB 动态代理 AspectJ静态代理区别 1.1. AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表:而动态代理则以 spring AOP 为代表 1 1.2. JDK动态代理是模拟接口实现的方式,cglib是模拟子类继承的方式1 1.3. CGLIB代理模式的缺点 在static和final方法上应用横切关注点也是无法做到的.2 1.1. AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表:而动态代理则以 

(转)Java动态代理与CGLib代理

本文通过spring aop的代理实现简述了java动态代理和cglib的区别,有助于理解java的代理模式 转载自:http://www.iteye.com/topic/182654 Java代码 <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        // TODO Auto-generated method stub <br>        Sys

WCF技术剖析之九:服务代理不能得到及时关闭会有什么后果?

原文:WCF技术剖析之九:服务代理不能得到及时关闭会有什么后果? 我们想对WCF具有一定了解的人都会知道:在客户端通过服务调用进行服务调用过程中,服务代理应该及时关闭.但是如果服务的代理不等得到及时的关闭,到底具有怎样的后果?什么要关闭服务代理?在任何时候都需要关闭服务代理吗?是否有一些例外呢?本篇文章将会围绕着这些问题展开. 一.会话信道(Sessionful Channel) V.S. 数据报信道(Datagram Channel) WCF通过信道栈实现了消息的编码.传输及基于某些特殊功能对

Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. cglib封装了asm,可以在运行期动态生成新的class. cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制. 原理区别: java动态代理是利用反射机

java 代理模式(静态代理、动态代理、Cglib代理) 转载

Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法 代理模式最大的特点就是代理类和实际业务类实现同一个接口(或继承同一父类),代理对象持有一个实际对象的引用,外部调用时操作的是代理对象,而在代理对象的内部实现中又会去调