Java动态代理

转:http://blog.csdn.net/zsmj_2011/article/details/10394805

代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象时,客户端实际上不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时,我们就可以返回该对象的代理。

通常情况下,适用代理模式的情况有两种:

1.创建对象开销很大,可以创建一个代理对象,推迟真正的对象创建。大家所熟悉的Hibernate延迟加载策略就是使用动态代理,当A实体关联B实体时,在获取A实体时不需要立即获得与A实体关联的B实体,因为有可能客户端根本不需要B实体数据,当客户端真正需要这部分数据时,再加载B实体的数据。这样就节省了资源。

2.所创建的对象不能满足客户端需求,比如说我们需要为某个方法运行前加入一些验证或者过滤,这时我们就需要创建一个代理对象,增强原来对象的功能。


java实现动态代理有两种方法:jdk代理和cglib。

jdk动态代理

jdk代理需要使用一个接口( InvocationHandler)和一个类( Proxy
InvocationHandler接口定义如下:
[java]  view plain copy print ?
  1. public interface InvocationHandler {   
  2. public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;   
  3. }   
代理类要实现这个接口,并实现Invoke方法,这个就是代理方法,当客户端调用委托对象方法时,实际上执行Invoke方法。
Proxy类提供了静态方法来获取动态代理对象:
[java]  view plain copy print ?
  1. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,   
  2. InvocationHandler h) throws IllegalArgumentException  
下面看一个jdk动态代理的例子:
首先定义一个接口
[java]  view plain copy print ?
  1. public interface IPerson {  
  2.   
  3.     void walk();  
  4. }  
定义实现类
[java]  view plain copy print ?
  1. public class Person implements IPerson {  
  2.   
  3.     @Override  
  4.     public void walk() {  
  5.         System.out.println("walk");  
  6.     }  
  7.   
  8. }  
定义代理实现类
[java]  view plain copy print ?
  1. public class MyInvokationHandler implements InvocationHandler {  
  2.   
  3.     private Object target;  
  4.     public void setTarget(Object target) {  
  5.         this.target=target;  
  6.     }  
  7.     /** 
  8.      * 执行动态代理对象的所有方法时,都会被替换执行如下的invoke方法 
  9.      * Proxy:代表动态代理的对象 
  10.      * method:代表正在执行的方法 
  11.      * args:代表调用目标方法时传入的参数 
  12.      */  
  13.     @Override  
  14.     public Object invoke(Object proxy, Method method, Object[] args)  
  15.             throws Throwable {  
  16.         System.out.println("正在执行的方法:"+method);  
  17.         method.invoke(target, args);  
  18.         return null;  
  19.     }  
  20.   
  21. }  

main函数
[java]  view plain copy print ?
  1. public class ProxyTest {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.   
  8.         MyInvokationHandler handler =new MyInvokationHandler();  
  9.         Person person=new Person();  
  10.         handler.setTarget(person);  
  11.         IPerson p=(IPerson)Proxy.newProxyInstance(Person.class.getClassLoader(), Person.class.getInterfaces(), handler);  
  12.         p.walk();  
  13.     }  
  14.   
  15. }  

这就是jdk动态代理的基本用法,是不是显的很麻烦,必须要使用接口,如果程序很简单,不想用接口,那么就不能使用jdk动态代理技术。

为什么jdk动态代理必须要使用接口呢?

原因是,jdk动态代理实际是要根据接口创建新的实现类,来实现代理方法。那么对于不是面向接口编程的程序,就无法使用jdk动态代理了,这时cglib解决了这个问题,cglib使用继承来创建代理类,因此可以传入普通类而不是接口来实现代理类,但是对于final类,无法实现动态代理。

cglib动态代理

和jdk动态代理使用方法类似,示例如下:

1、创建一个实现net.sf.cglib.proxy.MethodInterceptor接口的实例来为目标业务类加入进行代理时要进行的操作或增强:

[java]  view plain copy print ?
  1. import java.lang.reflect.Method;  
  2. import net.sf.cglib.proxy.MethodProxy;  
  3. import net.sf.cglib.proxy.Enhancer;  
  4. import net.sf.cglib.proxy.MethodInterceptor;  
  5. /** 
  6.  *CGlib采用非常底层的字节码技术,可以为一个类创建子类, 
  7.  并在子类中采用方法拦截技术拦截父类方法的调用,并顺势进行增强,即是织入横切逻辑 
  8.  * @author tufu 
  9.  */  
  10. public class CglibProxy implements MethodInterceptor{  
  11.     private Enhancer enhancer = new Enhancer();  
  12.     //覆盖MethodInterceptor接口的getProxy()方法,设置  
  13.     public Object getProxy(Class clazz){  
  14.         enhancer.setSuperclass(clazz); //设者要创建子类的类  
  15.         enhancer.setCallback(this); //设置回调的对象  
  16.         return enhancer.create(); //通过字节码技术动态创建子类实例,  
  17.     }  
  18.   
  19.     public Object intercept(Object obj,Method method,Object[] args,  
  20.             MethodProxy proxy) throws Throwable {  
  21.         System.out.println("模拟代理增强方法");  
  22.   
  23.         //通过代理类实例调用父类的方法,即是目标业务类方法的调用  
  24.         Object result = proxy.invokeSuper(obj, args);  
  25.   
  26.         System.out.println("模拟代理增强方法结束");  
  27.         return result;  
  28.     }  
  29. }  


2、通过java.lang.reflect.Proxy的getProxy()动态生成目标业务类的子类,即是代理类,再由此得到代理实例:

[java]  view plain copy print ?
  1. import com.proxy.ForumServiceImpl;  
  2. import java.lang.reflect.Proxy;  
  3.   
  4. public class TestCglibProxy {  
  5.     public static void main(String args[]){  
  6.         CglibProxy proxy = new CglibProxy();  
  7.   
  8.         //动态生成子类的方法创建代理类  
  9.         ForumServiceImpl fsi =  
  10.                 (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class);  
  11.   
  12.         fsi.removeForum(10);  
  13.         fsi.removeTopic(2);  
  14.     }  
  15. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值