Java动态代理

代理模式有很多种,包括静态代理,保护代理,远程代理,动态代理等等,每一种都有特定的使用场景。本文主要介绍Java中的动态代理。

一、静态代理和动态代理的区别

       首先给出静态代理和动态代理的定义:

       静态代理:由程序员创建,或由工具自动生成源代码,然后进行编译。运行期间,代理的class文件已经存在。

       动态代理:程序运行时,通过反射机制动态创建而成。

       所谓代理模式,就是通过一个代理类,间接调用一个具体类的方法,这个具体的类,叫委托类。用另一种话描述,静态代理,是给每一个具体的类写一个代理类,需要用到具体类的时候,就给这个具体的类写一个代理类,然后调用代理类就行了。

       但是这样,会有一个很大的缺点,如果有很多具体类,就需要些很多个代理类,这样无疑产生了很多重复代码。所以如果需要用一个代理类,完成所有的接口,就只能使用动态代理来完成。

 

二、动态代理示例

       动态代理,使用了一个接口InvocationHandler,和一个代理类Proxy, 二者配合完成动态代理的功能。示例代码如下:

       

Interface Demo {
    void sayHello();
}
class Demo implements IDemo {
    @Override
    public void sayHello() {
        System.out.println("Hello World");
    }
}

class DynamicInvoke implements InvocationHandler {
    Object obj;
    
    Object bind(Object obj) {
         this.obj = obj;
         return Proxy.newProxyInstance(
             obj.getClass().getClasslocader(),
             obj.getClass().getInterfaces(),
             this 
         );
         
         @Override
         public Object invoke(Object proxy, Method method, Object[] args) {
              return method.invoke(obj,args);    

         }
    }
}

class Client {
    public static void main(String[] args) {
         IDemo demo = (IDemo) new DynamicInvoke().bind(new Demo());
         demo.sayHello();
}

       上面的代码中,DynamicInvoke实现了InvocationHandler接口,也实现了invoke方法。同时,用Proxy.newProxyInstance()方法,创建了一个代理对象,那么使用这个代理对象,就可以调用具体类的方法。

       对应上面的代码,bind()方法中,用Proxy.newProxyInstance()方法,创建了了一个代理对象,main()中是demo对象。使用demo.sayHello(),就可以调用具体类Demo的对象才能调用的sayHello()方法,就达到了效果。另外,如果又创建了一个实现了IDemo接口的Demo1具体类,那么只要在bind参数中,传入Demo1的对象就可以。


三、newProxyInstance方法说明

      上面的代码中,比较有用的就两个,invoke()和newProxyInstance().

  ①invoke方法,第二个参数,Method类,Java反射reflection API中一部分,使用method.getName(),就可以知道proxy被调用的方法是什么。

    public Object invoke(Object proxy, Method method, Object[] args) {
          return method.invoke(obj,args);  //obj是被调用的真正对象  
    }
</pre><span style="font-family:Microsoft YaHei; font-size:12px"><span style="color:rgb(0,153,0); font-family:'Microsoft YaHei'; font-size:12px">  ②</span><span style="font-family:'Microsoft YaHei'; font-size:12px"><span style="color:#3333ff">newProxyInstance()方法,</span></span></span><p></p><p><span style="font-family:Microsoft YaHei; font-size:12px"><span style="color:rgb(0,153,0); font-family:'Microsoft YaHei'; font-size:12px">     </span><span style="font-family:'Microsoft YaHei'; font-size:12px"><span style="color:#3333ff">第二个参数是一个接口数组。</span></span></span><span style="font-family:'Microsoft YaHei'; font-size:12px"><span style="color:#3333ff">  该数组中只能有接口,不能有类。如果接口不是public的,那么必须属于同一个package,不同的接口内,不可以有名称和参数完全一样的方法。</span></span><span style="color:rgb(0,153,0); font-family:'Microsoft YaHei'; font-size:12px">  </span></p><p><span style="font-family:Microsoft YaHei; font-size:12px"></span></p><pre name="code" class="java">    Proxy.newProxyInstance(
         obj.getClass().getClasslocader(),
         obj.getClass().getInterfaces(),
         this 
    );
      跟踪这个方法,可以看到程序进行了验证,优化,缓存,生成字节码,显示加载等操作,最后调用了sun.misc.ProxyGenerator.generateProxyClass()来完成生成字节码的功能。








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值