Java动态代理InvocationHandler+Proxy

 
在很多时候都要使用到代理模式,其实静态代理很好理解,看代码也知道,但觉得动态代理InvocationHandler+Proxy觉得听奇怪的,不知道思考的结果对不对,贴上来:
静态代理模式:
interface Subject
{
    public String say(String name,int age);
}

class RealSubject implements Subject
{
    public String say(String name,int age)
    {
        return "name: "+name+" age: "+age;
    }
}

class ProxySubject implements Subject
{
    private Subject sub;
    ProxySubject(Subject sub)
    {
        this.sub = sub;
    }
    public String say(String name,int age)
    {
        return this.sub.say(name,age);
    }
}

public class DynaProxyDemo
{
    public static void main(String args[])
    {
        Subject sub = new ProxySubject(new RealSubject());
        String info = sub.say("cilen",22);
        System.out.println(info);
   
    }
}
代码很简单,就让代理去跟真正的业务类指向同一个对象,而不让用户直接操作真正的业务对象,同时可以增加额外的控制,比如在这里调用say()时候,代理中可以添加更多的执行命令或控制
静态代理,一个代理只能为一个接口服务,要是有很多接口,则需要有很多的代理类,而所有代理除了调用操作不一样,其他都一样,所以会造成很多重复的代码---使用动态代理

动态代理:

interface Subject
{
    public void request();
}


public class RealSubject1 implements Subject
{
    public void request()
    {
        System.out.println("now subject NO.1 is requesting...");
    }
}
public class RealSubject2 implements Subject
{
    public void request()
    {
        System.out.println("now subject NO.2 is requesting...");
    }
}
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
public class DynamicSubject implements InvocationHandler
{
    private Object obj;
    public DynamicSubject(){}
    public DynamicSubject(Object obj)
    {
        this.obj = obj;
    }
   
    public Object invoke(Object obj ,Method method,Object[] args) throws Throwable
    {
        System.out.println("before calling :"+method);
        method.invoke(this.obj,args);
        System.out.println("after calling:"+method);
        return null;
    }
   
}

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.Class;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
public class Client
{
    public static void main(String args[])
    {
        RealSubject1 rs = new RealSubject1();
//要修改为不同的对象,修改这句即可,RealSubject2 rs = new RealSubject2();
        InvocationHandler  ds = new DynamicSubject(rs);
        Class cls = rs.getClass();
        Subject subject =(Subject) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds);
        subject.request();
       
       

    }
}
其实不明白的就是invoke()方法,并没有出现显示的调用,那么为什么要实现InvocationHandler呢?其实不然,在Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds);其中的ds就是InvocationHandler 的具体对象,并且它在这里就是为了达到一种“注册”的作用。这个个代理接口的代理实例上(在这个理就是subject对象)的方法调用将被指派到实例的调用处理程序的invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
所以重要的情况发生了:如果不在invoke中通过Method的提供的相关手段执行方法,即便通过代理生成的对象有那个方法,但是却不是执行的那个方法,因为实际执行的是invoke方法,所以在invoke中应当执行完成对传过来的需要执行的方法的调用,通过method.invoke()使用相关参数即可完成,同时在调用
method.invoke之前还能进行一些别的操作

今天发现昨天的操作存在一些问题,首先在客户端还要进行Proxy的操作,觉得实在不合适。客户端应该是简单的生成相应的对象就好,所以将DynamicSubject和Client的代码修改如下:
DynamicClient:

import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class DynamicSubject implements InvocationHandler
{
    private Object obj;
    public DynamicSubject(){}
    public Object bind(Object obj)
    {
        this.obj = obj;
      Subject subject =(Subject) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),this);// 返回值是Object,所以要向下转型

      return subject ;
    }
   
    public Object invoke(Object obj ,Method method,Object[] args) throws Throwable
    {
        System.out.println("before calling :"+method);
        method.invoke(this.obj,args);
        System.out.println("after calling:"+method);
        return null;
    }
   
}


Client --大大缩小了这个代码量
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.Class;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
public class Client
{
    public static void main(String args[])
    {
        Subject sub = (Subject)new DynamicSubject().bind(new RealSubject2());
        sub.request();
       
       

    }
}
修改了生成真实对象的方式,不是让真实的对象作为参数传入动态代理,而是使用了bind()方法,虽说实质一样,但是看起来却有两种感觉,同时将 Proxy的操作放在了生成真实对象之后,显得也更直接和合理,同时最后多态的时候使用的是Subject的引用subject,而没有再使用 InvocationHandler也更符合习惯与规范...
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值