接着《 java设计模式——代理模式的应用与扩展(2)》继续讲
目录:
1)什么是动态代理
2)动态代理模板
动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理那一个对象,相对的来说,自己写代理类的方式就是静态代理。现在有一个非常流行的名称叫做:面向横切面编程,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制
我们还是以打游戏为例,将类图修改一下以实现动态代理,我们先来看看类图:
在类图中增加了一个InvocationHandler接口和GamePlayIH 类,作用就是产生一个对象的代理对象。其中InvocationHandler是JDK提供的动态代理接口,对被代理类的方法进行代理。
public interface IGamePlayer {
//登录游戏
public void login(String user,String password);
//杀怪,这是网络游戏的主要特色
public void killBoss();
//升级
public void upgrade();
}
public class GamePlayer implements IGamePlayer {
private String name = "";
//通过构造函数传递名称
public GamePlayer(String _name){
this.name = _name;
}
//打怪,最期望的就是杀老怪
public void killBoss() {
System.out.println(this.name + "在打怪!");
}
//进游戏之前你肯定要登录吧,这是一个必要条件
public void login(String user, String password) {
System.out.println("登录名为"+user + " 的用户 " + this.name + "登录成功!");
}
//升级,升级有很多方法,花钱买是一种,做任务也是一种
public void upgrade() {
System.out.println(this.name + " 又升了一级!");
}
}
public class GamePlayIH implements InvocationHandler {
//被代理者
Class> cls =null;
//被代理的实例
Object obj = null;
//我要代理谁
public GamePlayIH(Object _obj){
this.obj = _obj;
}
@Override
//调用被代理的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
Object result = method.invoke(this.obj, args);
return result;
}
}
其中invoke方法是接口InvocationHandler定义必须实现的,它完成对真实方法的调用。
我们来详细讲解一下InvocationHanlder接口,动态代理是根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称“我已经实现该接口下的所有方法了”,那各位读者想想看,动态代理怎么才能实现被代理接口中的方法呢?默认情况下所有的方法返回值都是空的,是的,代理已经实现它了,但是没有任何的逻辑含义,那怎么办?好办,通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。
public class Client {
public static void main(String[] args) throws Throwable {
//定义一个痴迷的玩家
IGamePlayer player = new GamePlayer("张三");
//定义一个hanlder
InvocationHandler handler = new GamePlayIH(player);
//开始打游戏,记下时间戳
System.out.println("开始时间是:2009-8-25 10:45");
//获得类的class loader
ClassLoader cl = player.getClass().getClassLoader();
//动态产生一个代理者
IGamePlayer proxy = (IGamePlayer)Proxy.newProxyInstance(cl,new Class[]{IGamePlayer.class},handler);
//登录
proxy.login("zhangSan", "password");
//开始杀怪
proxy.killBoss();
//升级
proxy.upgrade();
//记录结束游戏时间
System.out.println("结束时间是:2009-8-26 03:40");
}
}
我们还是让代练者帮我们打游戏,但是我们既没有创建代理类,也没有实现IGamePlayer接口,这就是动态代理!
不懂是吧?那我们继续往下看
现在我们如果想让游戏登录后发一个信息给我们,防止账号被人盗用,怎么做?可能大家第一反应是修改被代理类GamePlayer,但这不是好办法,我们看好办法:
看红色框框里面,只要在代理中增加一个判断就可以决定是否要发送信息。运行结果如下:
太棒了,有人用我的账号就发送一条信息给我,然后看看自己的账号是不是被人盗了,非常好,这就是AOP编程。
AOP编程没有使用什么新的技术,但是它对我们的设计,编码有非常大的影响,对于日志,事务,权限等都可以在系统设计阶段不用考虑,而在设计后用过AOP的方式切过去。
先来看看类图:
两条独立发展的路线。动态代理实现代理职责,业务逻辑Subject实现相关逻辑功能,两者之间没有必然的相互耦合的关系。
通知Advice从另一个切面切入,最终在高层模块也就是Client耦合,完成封装任务。
public interface Subject {
//业务操作
public void doSomething(String abc);
}
public class RealSubject implements Subject {
//业务操作
public void doSomething(String str) {
System.out.println("do something!---->" + str);
}
}
public class MyInvocationHandler implements InvocationHandler {
//被代理的对象
private Object target = null;
//通过构造函数传递一个对象
public MyInvocationHandler(Object _obj){
this.target = _obj;
}
//代理方法
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
//执行被代理的方法
return method.invoke(this.target, args);
}
}
所有通过动态代理实现的方法全部通过invoke方法调用。
public interface IAdvice {
//通知只有一个方法,执行即可
public void exec();
}
public class BeforeAdvice implements IAdvice{
public void exec(){
System.out.println("我是前置通知,我被执行了!");
}
}
public class DynamicProxy {
public static T newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h){
//寻找JoinPoint连接点,AOP框架使用元数据定义
if(true){
(new BeforeAdvice()).exec(); //执行一个前置通知
}
//执行目标,并返回结果
return (T)Proxy.newProxyInstance(loader,interfaces, h);
}
}