zoukankan      html  css  js  c++  java
  • java代理机制

    一、一般情况下处理业务的方法

    只要实现处理业务逻辑的代码就行了。比如下面的DoSomething中的doSomething()方法为模拟处理业务的代码。客户端只要调用DoSomething中doSomething()方法即可

    处理业务代码DoSomething.java

     1 import java.util.Random;
     2 
     3 public class DoSomething {
     4     public void doSomething(){
     5         System.out.println("doing something...");
     6         try {
     7             Thread.sleep((new Random().nextInt(2000)));                                    //模拟处理需要时间
     8         } catch (InterruptedException e) {
     9             e.printStackTrace();
    10         }
    11     }
    12 }

    客户端调用代码Client.java

    1 public class Client {
    2     public static void main(String args[]){
    3         DoSomething doSomething = new DoSomething();
    4         doSomething.doSomething();
    5     }
    6 }

    现在需要在控制台输出这个方法的执行时间,该怎么实现呢

    直接在doSomething()方法中添加开始时间和结束时间的代码,输出执行时间。DoSomething.java代码如下所示

     1 import java.util.Random;
     2 
     3 public class DoSomething {
     4     public void doSomething(){
     5         long startTime = System.currentTimeMillis();
     6         System.out.println("doing something...");
     7         try {
     8             Thread.sleep((new Random().nextInt(2000)));                                    //模拟处理需要时间
     9         } catch (InterruptedException e) {
    10             e.printStackTrace();
    11         }
    12         long endTime = System.currentTimeMillis();
    13         
    14         System.out.println("执行任务耗时:" + (endTime - startTime) + "毫秒");
    15     }
    16 }

    从输出可以看到功能已经实现。

    但是,这样代码耦合度会增加。如果我不需要输出执行时间,每一个方法都需要去修改。不利于代码重用

    二、设计模式纸代理模式Proxy

    上面为什么代码耦合度会高呢,主要是业务逻辑代码和分支代码混在一起。把这两个分开,即可解耦。这里可以利用设计模式里面的代理模式

    下面是代理模式的UML图

    从图中可以看出代理模式和实际业务处理共同实现了一个接口,这样在客户端就可以面向接口编程了。在ProxySubject中有RealSubject的引用,在代理中可以调用RealSubject的方法。同时,可以在调用RealSubject的方法时候进行其他处理。比如前面所说的计算所耗费的时间等...

    将上面的的代码按照Proxy模式实现。先定义一个接口,接口中为RealSubject中所有的方法。这里就是上面DoSomething中的doSomething()方法。代理类和RealSubject分别实现这个接口。代理类添加RealSubject的引用。在客户端使用代理。

    代码如下所示

    IDoSomething.java对应上图中的Subject

    1 public interface IDoSomething {
    2     public void doSomething();
    3 }

    DoSomething.java对应上图中的RealSubject

     1 public class DoSomething implements IDoSomething {
     2 
     3     @Override
     4     public void doSomething() {
     5         System.out.println("doing something...");
     6         try {
     7             Thread.sleep((new Random().nextInt(2000)));                                    //模拟处理需要时间
     8         } catch (InterruptedException e) {
     9             e.printStackTrace();
    10         }
    11 
    12     }
    13 
    14 }

    Proxy.java对应上图中的ProxySubject

     1 public class Proxy implements IDoSomething {
     2     IDoSomething doSomething = new DoSomething();                                        //实际处理类引用
     3     
     4     
     5     @Override
     6     public void doSomething() {
     7         long startTime = System.currentTimeMillis();
     8         doSomething.doSomething();                                                         //处理业务的方法
     9         long endTime = System.currentTimeMillis();
    10         
    11         System.out.println("执行任务耗时:" + (endTime - startTime) + "毫秒");
    12 
    13     }
    14 
    15 }

    Client.java

    1 public class Client {
    2 
    3     public static void main(String[] args) {
    4         IDoSomething doSomeThingProxy = new Proxy();                        
    5         doSomeThingProxy.doSomething();                                                    //调用代理类的方法
    6     }
    7 
    8 }

    这样就实现了两种代码的分离,降低代码耦合度

    但是这样也有缺点。这里实现的Subject类型的代理,如果我有很多种类型呢。是不是需要为每一种类型写代理呢。java代理机制提供了一种解决方案。动态代理机制

    三、java代理机制

    首先,先看一下java代理机制的UML图

    这里没有画出Client端。从上图中可以看出这里Proxy中没有直接引用RealSubject,而是引用了ProxyInHand对象。ProxyInHand中引用了RealSubject方法。(这里只是从UML中看出来的)

    这里先直接给出实现步骤

    首先让我们来了解一下如何使用 Java 动态代理。具体有如下四步骤:

    1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
    2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
    3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
    4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
    清单 3. 动态代理对象创建过程
    // InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
    // 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
    InvocationHandler handler = new InvocationHandlerImpl(..); 
    
    // 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
    Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 
    
    // 通过反射从生成的类对象获得构造函数对象
    Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); 
    
    // 通过构造函数对象创建动态代理类实例
    Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });

    实际使用过程更加简单,因为 Proxy 的静态方法 newProxyInstance 已经为我们封装了步骤 2 到步骤 4 的过程,所以简化后的过程如下

    清单 4. 简化的动态代理对象创建过程
    // InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
    InvocationHandler handler = new InvocationHandlerImpl(..); 
    
    // 通过 Proxy 直接创建动态代理类实例
    Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, 
    	 new Class[] { Interface.class }, 
    	 handler );

    个人理解,先写好处理业务逻辑的代码RealSubject,实现InvocationHandler接口(java api) InvocationHandlerImpl,在InvocationHandlerImpl中调用RealSubject处理方法。通过

    Interface proxy = (Interface)Proxy.newProxyInstance( classLoader,  new Class[] { Interface.class },  handler );方法生成代理类

    参考:

    http://www.cnblogs.com/machine/archive/2013/02/21/2921345.html

    http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/

    http://blog.csdn.net/giserstone/article/details/17199755

    源码:http://files.cnblogs.com/files/luckygxf/JavaDynProxy.zip

  • 相关阅读:
    iOS 解析xml
    带滚动条html,js获取鼠标位置
    iOS ViewController利用代理页面传值
    Android Volley完全解析
    32位linux中无法使用AVD的解决方案
    8年前在公交上被年轻小伙打了,76岁大爷苦练功夫“复仇”成功...网友:大爷,你一定是天蝎座的吧
    退学,离家出走,卖房创业,在他即将烧完最后一笔钱时,获250万元融资
    夏普将在迪拜推出植物工厂种草莓
    国产手机出货量今年要追平苹果三星,到底有多难?
    原生ajax动态添加数据
  • 原文地址:https://www.cnblogs.com/luckygxf/p/4392345.html
Copyright © 2011-2022 走看看