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

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类关系图:

详细代码:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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; /** * 婚礼标准流程(接口): * A. 布置婚礼现场,不必情侣lovers亲自做,可由婚庆公司代理 * B. 结婚宣誓,必须由情侣亲自做 * C. 招待宾客(接迎),不必情侣lovers亲自做,可由婚庆公司代理 * @author Heiry * */ public interface Wedding { public void arrangement() ; //布置婚礼现场 public void weddingvows() ; //夫妻宣誓 public void entertainment(); //招待宾客 }
package net.mosang.agent;
/**
 *   婚礼标准流程(接口):
 *   A. 布置婚礼现场,不必情侣lovers亲自做,可由婚庆公司代理
 *   B. 结婚宣誓,必须由情侣亲自做
 *   C. 招待宾客(接迎),不必情侣lovers亲自做,可由婚庆公司代理
 * @author Heiry
 *
 */
public interface Wedding {
  public void arrangement() ; //布置婚礼现场
  public void weddingvows() ; //夫妻宣誓
  public void entertainment(); //招待宾客
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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; /** * 婚礼主角:情侣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;
/**
 *  婚礼主角:情侣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;
  }
  
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 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 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;
  }
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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; /** * 客户端测试 * @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;
/**
 * 客户端测试
 * @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();	
  }
}

输出结果

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
婚庆公司布置婚礼现场
新郎-->牛郎与新娘-->织女宣誓结婚
婚庆公司招待宾客
婚庆公司布置婚礼现场 新郎-->牛郎与新娘-->织女宣誓结婚 婚庆公司招待宾客
婚庆公司布置婚礼现场
新郎-->牛郎与新娘-->织女宣誓结婚
婚庆公司招待宾客

 

下面用动态代理来实现:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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.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.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;
  }
  

}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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();
}
}
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(); } }
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();
  }
}

输出结果:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
婚庆公司布置现场
新郎-->牛郎与新娘-->织女宣誓结婚
婚庆公司接送宾客
婚庆公司布置现场 新郎-->牛郎与新娘-->织女宣誓结婚 婚庆公司接送宾客
婚庆公司布置现场
新郎-->牛郎与新娘-->织女宣誓结婚
婚庆公司接送宾客

动态代理的实质探究

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package net.mosang.agent;
/**
* 代理模式深入探究
* @author Heiry
*
*/
public interface Dream {
public void doSomething();
}
package net.mosang.agent; /** * 代理模式深入探究 * @author Heiry * */ public interface Dream { public void doSomething(); }
package net.mosang.agent;
/**
 * 代理模式深入探究
 * @author Heiry
 *
 */
public interface Dream {
  public void doSomething();
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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; /** * 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;
/**
 * 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!");
  }
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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!”
}
}
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!” } }
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提供的动态代理机制允许在运行期动态创建接口的实例。

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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();
}
}
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(); } }
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();
  }

}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public abstract void net.mosang.agent.Dream.doSomething()
Your dream is wonderful!
public abstract void net.mosang.agent.Dream.doSomething() Your dream is wonderful!
public abstract void net.mosang.agent.Dream.doSomething()
Your dream is wonderful!

 

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

 >>



© 2009-2024 MOSANG.NET DESIGNED BY HEIRY