动态代理与静态代理最大的不同在于,动态代理中,代理类对象由JVM生成,不再需要我们自己编写代理类。
核心实现:
1. java.lang.reflect.Proxy类动态生成代理类和对象,它提供用于创建动态代理类和实例的静态方法,是由这些方法创建的所有动态代理类的超类。
2.java.lang.reflect.InvocationHandler处理器接口,可以通过invoke方法实现对真实角色的访问。(每次通过Proxy生成代理类对象时都要指定该处理器接口)
静态代理模式下,我们需要自定义代理类,其中UML类图如下:
动态代理模式下,代理类由Proxy类的静态方法newProxyInstance()创建,并关联处理器实例handler,而handler是继承自InvocationHandler接口的RoleHandler类的实例,handler包含了对真实角色RealRole的引用。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!
通过动态代码,我们可以动态实现一个接口的实例对象,实际上就是静态代理中的代理对象,只不过这个代理对象不是事先编写好的,而是运行期动态创建的。
>>