设计模式剖析系列之动态代理及原理探究

By heiry on 2019-08-17 [ in 技术 ]

java动态代理剖析

动态代理与静态代理最大的不同在于,动态代理中,代理类对象由JVM生成,不再需要我们自己编写代理类。

核心实现:

1. java.lang.reflect.Proxy类动态生成代理类和对象,它提供用于创建动态代理类和实例的静态方法,是由这些方法创建的所有动态代理类的超类。

2.java.lang.reflect.InvocationHandler处理器接口,可以通过invoke方法实现对真实角色的访问。(每次通过Proxy生成代理类对象时都要指定该处理器接口)

静态代理模式下,我们需要自定义代理类,其中UML类图如下:

 

动态代理模式下,代理类由Proxy类的静态方法newProxyInstance()创建,并关联处理器实例handler,而handler是继承自InvocationHandler接口的RoleHandler类的实例,handler包含了对真实角色RealRole的引用。UML类图如下:

java动态代理模式uml类图

 

 

我们先来看静态代理的实现(以婚礼为例说明):

UML类关系图:

详细代码:

package net.mosang.agent;
/**
 *   婚礼标准流程(接口):
 *   A. 布置婚礼现场,不必情侣lovers亲自做,可由婚庆公司代理
 *   B. 结婚宣誓,必须由情侣亲自做
 *   C. 招待宾客(接迎),不必情侣lovers亲自做,可由婚庆公司代理
 * @author Heiry
 *
 */
public interface Wedding {
  public void arrangement() ; //布置婚礼现场
  public void weddingvows() ; //夫妻宣誓
  public void entertainment(); //招待宾客
}
package net.mosang.agent;
/**
 *  婚礼主角:情侣Lovers,他们具备结婚标准流程要求的技能,但不一定需要用上
 *  
 * @author Heiry
 *
 */
public class Lovers implements Wedding{
  private String bridegroom; //新郎姓名
  private String bride; //新娘姓名
  @Override
  public void arrangement() {
    System.out.println("新郎:"+this.bridegroom +"与新娘:"+ this.bride + "布置了婚礼现场");//情侣亲自布置
  }
  @Override
  public void weddingvows() {
    System.out.println("新郎-->"+this.bridegroom +"与新娘-->"+ this.bride + "宣誓结婚"); // 情侣结婚宣誓词	
  }
  @Override
  public void entertainment() {
    System.out.println("新郎:"+this.bridegroom +"与新娘:"+ this.bride + "招待宾客");//情侣亲自接待宾客
  }
  public Lovers(String bridegroom, String bride) {
    super();
    this.bridegroom = bridegroom;
    this.bride = bride;
  }
  
}
package net.mosang.agent;
/**
 *  婚庆代理公司: 帮助情侣打理除了宣誓之外的所有事务
 * @author Heiry
 *
 */
public class WeddingAgent implements Wedding {
  private Lovers Lovers;
  @Override
  public void arrangement() {
    System.out.println("婚庆公司布置婚礼现场");//婚庆公司布置婚礼现场
  }
  @Override
  public void weddingvows() {
    Lovers.weddingvows(); //由情侣亲自做
  }
  @Override
  public void entertainment() {
    System.out.println("婚庆公司招待宾客");//婚庆公司招待宾客
  }
  public WeddingAgent(Lovers lovers) {
    super();
    this.Lovers = lovers;
  }
}
package net.mosang.agent;
/**
 * 客户端测试
 * @author Heiry
 *
 */
public class Client {
  public static void main(String[] args) {
    Lovers lovers = new Lovers("牛郎", "织女"); //创建牛郎织女新人实例
    WeddingAgent weddingAgent = new WeddingAgent(lovers); //创建婚庆公司实例
    /**
     *  整个婚礼完全由婚庆代理主导,外界无需知道婚礼主角在其中具体的操作
     */
    weddingAgent.arrangement();
    weddingAgent.weddingvows();
    weddingAgent.entertainment();	
  }
}

输出结果

婚庆公司布置婚礼现场
新郎-->牛郎与新娘-->织女宣誓结婚
婚庆公司招待宾客

 

下面用动态代理来实现:

package net.mosang.agent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class WeddingHandler implements InvocationHandler {
  private Lovers lovers;

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("婚庆公司布置现场");
    if(method.getName().equals("weddingvows")) {
      method.invoke(lovers, args);
    }
    System.out.println("婚庆公司接送宾客");
    return null;
  }

  public WeddingHandler(Lovers lovers) {
    super();
    this.lovers = lovers;
  }
  

}
package net.mosang.agent;

import java.lang.reflect.Proxy;

public class ClientDynamic {
  public static void main(String[] args) {
    Lovers lovers = new Lovers("牛郎", "织女");
    WeddingHandler weddingHandler = new WeddingHandler(lovers);
    Wedding proxy =(Wedding) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] {Wedding.class}, weddingHandler);
    proxy.weddingvows();
  }
}

输出结果:

婚庆公司布置现场
新郎-->牛郎与新娘-->织女宣誓结婚
婚庆公司接送宾客

动态代理的实质探究

通过以上代码,初学者对动态代理实现机制可能还是云里雾里,知其然不知其所以然,所以在这里还是有必要梳理清楚。

现在我们有一个接口Dream(代码如下),我们知道要使用一个接口,就要编写其实现类并实例化:

package net.mosang.agent;
/**
 * 代理模式深入探究
 * @author Heiry
 *
 */
public interface Dream {
  public void doSomething();
}
package net.mosang.agent;
/**
 * Dream接口的实现类MyDream
 * @author Heiry
 *
 */

public class MyDream implements Dream {
  @Override
  public void doSomething() {
    System.out.println("I wanna be a great program engineer,just like Dennis MacAlistair Ritchie!");
  }
}
package net.mosang.agent;
/**
 * 测试类
 * @author Heiry
 *
 */
public class DreamComeTrue {
  public static void main(String[] args) {
    Dream myDream = new MyDream(); //多态方式创建实例
    myDream.doSomething(); //输出“I wanna be a great program engineer,just like Dennis MacAlistair Ritchie!”
  }

}

如果我们不编写实现类,有没有办法运行期直接创建Dream的实现类?这似乎与接口的使用规则背道而驰,因为接口是不能实例化的,然而java提供的动态代理机制允许在运行期动态创建接口的实例。

这种没有实现类但在运行期动态创建了一个接口对象的方式,我们称为动态代码。

package net.mosang.agent;

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

/**
 * 测试类
 * @author Heiry
 *
 */
public class DreamComeTrue {
  public static void main(String[] args) {
//		Dream myDream = new MyDream(); //多态方式创建实例
//		myDream.doSomething();
    InvocationHandler handler = new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method);
        System.out.println("Your dream is wonderful!");
        return null;
      }
    };
    Dream yourDream = (Dream) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] {Dream.class}, handler);
    yourDream.doSomething();
  }

}
public abstract void net.mosang.agent.Dream.doSomething()
Your dream is wonderful!

 

通过动态代码,我们可以动态实现一个接口的实例对象,实际上就是静态代理中的代理对象,只不过这个代理对象不是事先编写好的,而是运行期动态创建的。

 >>



© 2009-2024 MOSANG.NET DESIGNED BY HEIRY