23种设计模式----------代理模式(三) 之 动态代理模式
当然代理模式中,用的最广泛的,用的最多的是 动态代理模式。
动态代理:就是实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。
抽象接口的类图如下:
--图来自设计模式之禅
所以动态代理模式要有一个InvocationHandler接口 和 GamePlayerIH实现类。其中 InvocationHandler是JD提供的动态代理接口,对被代理类的方法进行代理。
代码实现如下
抽象主题类或者接口:
1 package com.yemaozi.proxy.dynamic; 2 3 /* 4 * 动态代理:就是实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。 5 */ 6 public interface IGamePlayer { 7 //登录游戏 8 public void login(String username, String password); 9 10 //击杀Boss 11 public void killBoss(); 12 13 //升级 14 public void upGrade(); 15 }
需要被代理类:
1 package com.yemaozi.proxy.dynamic; 2 3 public class GamePlayer implements IGamePlayer { 4 5 private String name = ""; 6 7 public GamePlayer(String name){ 8 this.name = name; 9 } 10 11 public void login(String username, String password) { 12 System.out.println("登录名为 "+username+" 进入游戏," + name + " 登录成功!"); 13 } 14 15 public void killBoss() { 16 System.out.println(this.name + " 击杀了Boss!"); 17 } 18 19 public void upGrade() { 20 System.out.println(this.name + "升级了!"); 21 } 22 23 }
动态代理处理器类:
1 package com.yemaozi.proxy.dynamic; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class GamePlayerInvocationHandler implements InvocationHandler{ 7 8 //被代理的对象 9 private Object obj; 10 11 //将需要代理的实例通过处理器类的构造方法传递给代理。 12 public GamePlayerInvocationHandler(Object obj){ 13 this.obj = obj; 14 } 15 16 public Object invoke(Object proxy, Method method, Object[] args) 17 throws Throwable { 18 Object result = null; 19 if("login".equalsIgnoreCase(method.getName())){ 20 //这个在主题方法不受任何影响的情况下,在主题方法前后添加新的功能,或者增强主题方法, 21 //从侧面切入从而达到扩展的效果的编程,就是面向切面编程(AOP Aspect Oriented Programming)。 22 //AOP并不是新技术,而是相对于面向对象编程的一种新的编程思想。在日志,事务,权限等方面使用较多。 23 System.out.println("代理登录游戏!"); 24 result = method.invoke(this.obj, args); 25 return result; 26 } 27 result = method.invoke(this.obj, args); 28 return result; 29 } 30 31 }
由于代理是动态产生的,所以不需要再声明代理类。
动态代理场景类:
package com.yemaozi.proxy.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { IGamePlayer gp = new GamePlayer("张三"); InvocationHandler gpHandler = new GamePlayerInvocationHandler(gp); //获取真实主题类的ClassLoader ClassLoader classLoader = gp.getClass().getClassLoader(); //动态产生一个代理者。 Class<?>[] cls = new Class[]{IGamePlayer.class}; IGamePlayer proxyGp = (IGamePlayer) Proxy.newProxyInstance(classLoader, cls, gpHandler); proxyGp.login("zhangsan", "123456"); proxyGp.killBoss(); proxyGp.upGrade(); } } 执行结果: 代理登录游戏! 登录名为 zhangsan 进入游戏,张三 登录成功! 张三 击杀了Boss! 张三升级了! //在此,我们没有创建代理类,但是确实有代理类帮我们完成事情。
其中,在此代理模式中,不仅代理是动态产生的(即在运行的时候生成),而且还在代理的时候,也增加了一些处理。在此处增加的处理,其实就是另一种编程思想-----面向切面编程思想(AOP Aspect Oriented Programming)。
带有AOP的动态代理模式类图:
--图来自设计模式之禅
从上图中,可以看出有两个相对独立的模块(Subject和InvocationHandler)。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。然而,通知Advice从另一个切面切入,最终在上层模块就是Client耦合,完成逻辑的封装。
代码清单如下
抽象主题或者接口:
1 package com.yemaozi.proxy.dynamic_aop; 2 3 public interface Subject { 4 public void doSomething(String str); 5 //...可以多个逻辑处理方法。。。 6 }
真实主题:
1 package com.yemaozi.proxy.dynamic_aop; 2 3 public class RealSubject implements Subject{ 4 5 public void doSomething(String str) { 6 //do something... 7 System.out.println("do something..." + str); 8 } 9 10 }
通知接口:
1 package com.yemaozi.proxy.dynamic_aop; 2 3 //通知接口及定义、 4 public interface IAdvice { 5 public void exec(); 6 }
前置通知:
1 package com.yemaozi.proxy.dynamic_aop; 2 3 public class BeforeAdvice implements IAdvice { 4 //在被代理的方法前来执行,从而达到扩展功能。 5 public void exec() { 6 System.out.println("前置通知被执行!"); 7 } 8 }
后置通知:
1 package com.yemaozi.proxy.dynamic_aop; 2 3 public class AfterAdvice implements IAdvice { 4 5 //在被代理的方法后来执行,从而达到扩展功能。 6 public void exec() { 7 System.out.println("后置通知被执行!"); 8 } 9 }
动态代理的处理器类:
所有的方法通过invoke方法类实现。
1 package com.yemaozi.proxy.dynamic_aop; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class MyInvocationHandler implements InvocationHandler { 7 8 //被代理的对象 9 private Subject realSubject; 10 //通过MyInvocationHandler的构造方法将被代理对象传递过来。 11 public MyInvocationHandler(Subject realSubject){ 12 this.realSubject = realSubject; 13 } 14 //执行被代理类的方法。 15 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 16 //在执行方法前,执行前置通知。 17 IAdvice beforeAdvice = new BeforeAdvice(); 18 beforeAdvice.exec(); 19 Object result = method.invoke(this.realSubject, args); 20 //在执行方法后,执行后置通知。 21 IAdvice afterAdvice = new AfterAdvice(); 22 afterAdvice.exec(); 23 //前置通知,和后置通知,都是要看具体实际的业务需求来进行添加。 24 return result; 25 } 26 27 }
动态代理类:
1 package com.yemaozi.proxy.dynamic_aop; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 public class DynamicProxy { 7 8 /** 9 * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler) 10 * loader: 11 * 一个ClassLoader对象,定义了由哪个ClassLoader对象,来对生产的代理进行加载。 12 * interfaces: 13 * 一个Interfaces数组,表示我将要给我所代理的对象提供一组什么样的接口, 14 * 如果提供一组接口给它,那么该代理对象就宣称实现了该接口,从而可以调用接口中的方法。 15 * 即,查找出真是主题类的所实现的所有的接口。 16 * handler: 17 * 一个InvocationHandler对象,表示当我这个动态代理对象在调用方法时,会关联到该InvocationHandler对象。 18 * 该InvocationHandler与主题类有着关联。 19 */ 20 public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){ 21 @SuppressWarnings("unchecked") 22 T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler); 23 return t; 24 } 25 }
从动态的产生动态代理类。
动态代理场景类:
1 package com.yemaozi.proxy.dynamic_aop; 2 3 import java.lang.reflect.InvocationHandler; 4 5 public class AOPClient { 6 7 public static void main(String[] args) { 8 Subject realSubject = new RealSubject(); 9 InvocationHandler handler = new MyInvocationHandler(realSubject); 10 ClassLoader classLoader = realSubject.getClass().getClassLoader(); 11 Class<?>[] interfaces = realSubject.getClass().getInterfaces(); 12 Subject proxySubect = DynamicProxy.newProxyInstance(classLoader, interfaces, handler); 13 proxySubect.doSomething("这是一个Dynamic AOP示例!!!"); 14 } 15 } 16 17 执行结果: 18 前置通知被执行! 19 do something...这是一个Dynamic AOP示例!!! 20 后置通知被执行!
动态代理中invoke的动态调用:
动态代理类DynamicProxy是个纯粹的动态创建代理类通用类。
所以在具体业务中,可以在进一步封装具体的具有业务逻辑意义的DynamicProxy类。
代码如下
具体业务的动态代理:
1 package com.yemaozi.proxy.dynamic_aop; 2 3 import java.lang.reflect.InvocationHandler; 4 //具体业务的动态代理。 5 public class SubjectDynamicProxy extends DynamicProxy { 6 public static <T> T newProxyInstance(Subject subject){ 7 ClassLoader classLoader = subject.getClass().getClassLoader(); 8 Class<?>[] interfaces = subject.getClass().getInterfaces(); 9 InvocationHandler handler = new MyInvocationHandler(subject); 10 T t = newProxyInstance(classLoader, interfaces, handler); 11 return t; 12 } 13 }
动态代理在现在用的是非常的多的,如像Spring AOP ,DBCP连接池,AspectJ等。。。