动态代理模式

什么是动态代理

动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态代理。
现在有一个非常流行的名称叫做面向切面编程,也就是AOP(Aspect Oriented Programming)其核心就是采用了动态代理机制。

动态代理模式简单类图

这里写图片描述

(以gameplay为例)
这里写图片描述

上图中InvocationHandle接口和GamePlayIH类 作用就是产生一个对象的代理对象,其中InvocationHandle是JDK提供的动态代理接口,对被代理类的方法进行代理

GamePlayIH类代码如下

package dynamicproxypatern;

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

public class GamePlayIH implements InvocationHandler {

    //被代理的实例
    Object obj = null;
    //我要代理谁
    public GamePlayIH(Object _obj) {
        this.obj = _obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        Object result = method.invoke(this.obj, args);
        return result;
    }

}

其中invoke方法是InvocationHandler接口中定义必须实现的,它完成对真实方法的调用。
InvocationHandler接口介绍,动态代理根据被代理的接口生成所有的方法,只是所有的方法都是空的,通过InvocationHandler接口,把所有的方法交由该Handle处理。即所有被代理的方法都有InvocationHandler接管实际的处理任务。

抽象主题角色(游戏玩家接口)代码如下

package dynamicproxypatern;

public interface IGamePlayer {

    public void login(String user,String password);
    public void killBoss();
    public void upgrade();
}

具体主题角色(具体玩家类)代码如下

package dynamicproxypatern;

public class GamePlayer implements IGamePlayer {

    private String name = "";
    public GamePlayer(String _name) {
        this.name = _name;
    }
    @Override
    public void login(String user, String password) {
        // TODO Auto-generated method stub
        System.out.println("登录名为" + user + "的用户   " + this.name + "登录成功!");
    }

    @Override
    public void killBoss() {
        // TODO Auto-generated method stub
        System.out.println(this.name + "在打怪!");
    }

    @Override
    public void upgrade() {
        // TODO Auto-generated method stub
        System.out.println(this.name + "又升了一级!");
    }

}

客户端测试类

package dynamicproxypatern;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.time.LocalDateTime;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IGamePlayer player = new GamePlayer("张三");
        InvocationHandler handler = new GamePlayIH(player);
        System.out.println("开始时间是:" + LocalDateTime.now());
        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("结束时间是:" + LocalDateTime.now());
    }

}

输出结果为
开始时间是:2017-09-29T15:52:15.356
登录名为zhangsan的用户 张三登录成功!
张三在打怪!
张三又升了一级!
结束时间是:2017-09-29T15:52:15.360


客户端测试类另一种写法

import java.time.LocalDateTime;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IGamePlayer player = new GamePlayer("张三");
        InvocationHandler handler = new GamePlayIH(player);
        System.out.println("开始时间是:" + LocalDateTime.now());
        Class c = player.getClass();
        IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), handler);
        proxy.login("zhangsan", "password");
        proxy.killBoss();
        proxy.upgrade();
        System.out.println("结束时间是:" + LocalDateTime.now());
    }

}

如何在游戏登录后发送消息?

修改下代理类,是代理类的方法代理为login方法时,处理一些事情

package dynamicproxypatern;

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

public class GamePlayIH implements InvocationHandler {

    //被代理的实例
    Object obj = null;
    //我要代理谁
    public GamePlayIH(Object _obj) {
        this.obj = _obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        Object result = method.invoke(this.obj, args);
        if(method.getName().equals("login")) {
            System.out.println("登录时发送一些消息");
        }
        return result;
    }

}

其他的类都不用动,输出结果为
开始时间是:2017-09-29T15:59:50.307
登录名为zhangsan的用户 张三登录成功!
登录时发送一些消息
张三在打怪!
张三又升了一级!
结束时间是:2017-09-29T15:59:50.311

以上的发送消息就是AOP编程,使得我们在设计系统时不用考虑日志、事务、权限等等,而是在设计以后用AOP的方式切过去。


动态代理通用形式和代码

动态代理的通用类图如下(重点)
这里写图片描述
由上图可以看出两条独立发展的线路,动态代理实现代理的职责,subject实现相关的逻辑功能,advice(通知)从另一个切面切入,然后在高层模块也就是client进行耦合。

代码展示

抽象主题类

package dynamicproxypatern;

public interface Subject {
    //业务操作
    public void doSomething(String str);
}

具体主题类

package dynamicproxypatern;

public class RealSubject implements Subject {

    @Override
    public void doSomething(String str) {
        // TODO Auto-generated method stub
        System.out.println("do something --->" + str);
    }

}

通知接口

package dynamicproxypatern;

public interface IAdvice {

    public void exec();
}

前置通知类

package dynamicproxypatern;

public class BeforeAdvice implements IAdvice {

    @Override
    public void exec() {
        // TODO Auto-generated method stub
        System.out.println("我是前置通知,先执行了我");
    }

}

动态代理的Handle类

package dynamicproxypatern;

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

public class MyInvocationHandler implements InvocationHandler {
    //被代理的对象
    Object obj = null;
    //我要代理谁
    public MyInvocationHandler(Object _obj) {
        this.obj = _obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        return method.invoke(this.obj, args);
    }

}

动态代理类

package dynamicproxypatern;

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

public class DynamicProxy<T> {

    public static <T> T newProxyInstance(ClassLoader loader,Class<?>[] 
            interfaces,InvocationHandler h) {
        if(true) {
            (new BeforeAdvice()).exec();
        }
        return  (T) Proxy.newProxyInstance(loader, interfaces, h);
    }
}

客户端测试类

package dynamicproxypatern;

import java.lang.reflect.InvocationHandler;
import java.time.LocalDateTime;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Subject subject = new RealSubject();
        InvocationHandler handler = new MyInvocationHandler(subject);
        Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(), 
                subject.getClass().getInterfaces(), handler);
        System.out.println("开始时间是:" + LocalDateTime.now());
        proxy.doSomething("测试一下");
        System.out.println("结束时间是:" + LocalDateTime.now());
    }
}

输出结果为
我是前置通知,先执行了我
开始时间是:2017-09-29T16:42:45.985
do something —>测试一下
结束时间是:2017-09-29T16:42:45.986


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值