设计模式之代理模式(3)

观看这篇文章前,请先阅读设计模式之代理模式(1)

静态代理会发生类爆炸?那jdk的使用的动态代理到底是怎么做到的呢?我来大概模拟一下jdk的动态代理。

这是我的目录结构:(可先跳过代码,到最下面听下我的BB,在对照代码来看!)

我先来介绍一下这些兄弟:

Tank:

package cn.asto.proxy;

import java.util.Random;

public class Tank implements Moveable{

    public void move(){
        System.out.println("Tank is moving...");
        try {
            Thread.sleep(new Random(47).nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

Moveable:

package cn.asto.proxy;

public interface Moveable {

    public void move();
}

InvocationHandler(一个接口):

package cn.asto.proxy;

import java.lang.reflect.Method;

public interface InvocationHandler {

    public void invoke(Object o,Method m);
}

TimeHandler(实现了InvocationHandler的接口)

package cn.asto.proxy;

import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler{

    private Object target;
    public TimeHandler(Object target){
        this.target = target;
    }

    @Override
    public void invoke(Object o, Method m)  {

        long startTime = System.currentTimeMillis();
        System.out.println("startTime:"+startTime);

        try {
            m.invoke(target,null);
        } catch (Exception e) {

            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Time:"+(endTime-startTime));

    }

}

Proxy(总代理):

package cn.asto.proxy;

import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Proxy {

    public static Object getProxyInstance(Class inface,InvocationHandler h) throws Exception{
        String rt ="\r\t";
        String methodStr = "";
//        for(Method m:inface.getMethods()){
//            methodStr+="    @Override" + rt+
//                        "    public void " + m.getName() + "(){" + rt +
//                        "            long startTime = System.currentTimeMillis();"+ rt +
//                        "            System.out.println(\"startTime:\"+startTime);"+ rt +
//                        "            t." + m.getName() + "()" + ";"+ rt +
//                        "            long endTime = System.currentTimeMillis();"+ rt +
//                        "            System.out.println(\"Time:\"+(endTime-startTime));"+ rt +
//
//                        "     }" + rt;
//
//        }
        for(Method m : inface.getMethods()) {
            methodStr += "@Override" + rt +
                         "public void " + m.getName() + "() {" + rt +
                         "    try {" + rt +
                         "    Method md = " + inface.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
                         "    h.invoke(this, md);" + rt +
                         "    }catch(Exception e) {e.printStackTrace();}" + rt +

                         "}";
        }

        String str = 

        "package cn.asto.proxy;"+ rt +
        "import java.lang.reflect.Method;" + rt +
        "public class TankTimeProxy implements    " +inface.getName()+ "{"+ rt +

        "   cn.asto.proxy.InvocationHandler h;" + rt +

        "    public TankTimeProxy(InvocationHandler h) {"+ rt +
        "        super();"+ rt +
        "        this.h = h;"+ rt +
        "}"+ rt +

            methodStr+

        "}";
        String fileName =System.getProperty("user.dir")+"/src/cn/asto/proxy/TankTimeProxy.java";
        FileWriter fw = new FileWriter(fileName);
        fw.write(str);
        fw.flush();
        fw.close();
        //compile
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileMgr.getJavaFileObjects(fileName);
        CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
        t.call();
        fileMgr.close();

        //load into memory and create an instance
        URL[] urls = new URL[]{(new URL("file:/"+System.getProperty("user.dir")+"/src/"))};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("cn.asto.proxy.TankTimeProxy");
        System.out.println(c);
        Constructor ctr = c.getConstructor(InvocationHandler.class);
        Object m = (Object)ctr.newInstance(h);
        return m;
    }
}

Test1:

package cn.asto.compiler.test;

import cn.asto.proxy.InvocationHandler;
import cn.asto.proxy.Moveable;
import cn.asto.proxy.Proxy;
import cn.asto.proxy.Tank;
import cn.asto.proxy.TimeHandler;

public class Test1 {

    public static void main(String args[]) throws Exception{
        Tank t = new Tank();
        InvocationHandler h = new TimeHandler(t);
        Moveable m = (Moveable)Proxy.getProxyInstance(Moveable.class, h);
        m.move();
    }
}

大概思路就是将代理添加的逻辑代码和基类抽象出来,我们都知道所有的代理类(以及基类实现一个接口),并且为了提高逻辑代码的重用性,我们将这两部分抽象成InvocationHandler和XXX.class.(xxx表示代理和基类实现的接口,这里是指Moveable),

写一个TimeHandler类,传入一个代理或者基类,实现InvocationHandler接口,将实现类和xxx.class作为Proxy的构造参数传入,在Proxy大概做那么几件事情,动态生成代理类文件(.java),编译,将InvocationHandler的实现类传入到动态代理文件的构造函数中,构造代理类。(这里有一个回调的过程),让动态代理类去回调InvocationHandler的实现类中的具体逻辑代码(invoke方法),而invoke调用的就是传给InvocationHandler实现类的构造参数类的需要实现逻辑代码添加的方法的基础上,加上逻辑代码。

现在让我们来做一个实验,验证动态代理类可以实现代理任意的对象和任意的逻辑方法体(InvocationHandler)

新建一个User接口:

package cn.asto.proxy.user;

public interface UserMgr {

    public void addUser();
}

建一个User类:

package cn.asto.proxy.user;

public class User implements UserMgr{

    @Override
    public void addUser() {
        System.out.println("添加用户");

    }

}

在建一个LoginHandler

package cn.asto.proxy.user;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import cn.asto.proxy.InvocationHandler;

public class LoginHandler implements InvocationHandler{

    private Object target;

    public LoginHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public void invoke(Object o, Method m) {
        System.out.println("登录成功");
        try {
            m.invoke(target, null);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

在Client中进行调用:

package cn.asto.proxy.user;

import cn.asto.proxy.Proxy;

public class Client {

    public static void main(String args[]){
        User u = new User();
        LoginHandler l = new LoginHandler(u);
        try {
            UserMgr ur = (UserMgr)Proxy.getProxyInstance(UserMgr.class, l);
            ur.addUser();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

打印输出:

登录成功
添加用户

测试完成!

好让我来看看jdk的代理程序:

package cn.asto.jdk;

import java.lang.reflect.Proxy;

import cn.asto.proxy.user.UserMgr;

public class Client {
    public static void main(String args[]){
        User u = new User();
        LoginHandler l = new LoginHandler(u);
        ClassLoader c = ClassLoader.getSystemClassLoader();
        try {
            UserMgr ur = (UserMgr)Proxy.newProxyInstance(c,new Class[]{UserMgr.class}, l);
            ur.addUser();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
package cn.asto.jdk;

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

public class LoginHandler implements InvocationHandler {

    private Object target;

    public LoginHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("登录成功");
        try {
            method.invoke(target, null);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}
package cn.asto.jdk;

import cn.asto.proxy.user.UserMgr;

public class User implements UserMgr{

    @Override
    public void addUser() {
        System.out.println("添加用户");

    }

}
package cn.asto.proxy.user;

public interface UserMgr {

    public void addUser();
}

不用看了,基本和我实现得差不多。只不过换成了jdk的InvocationHandler和jdk的Proxy.newProxyInstance

总结:代理可以完成代码块的插拔叠加!什么意思呢?spring中aop不就是这样子吗?    拦截器? 登录校验?权限控制?

时间: 2024-08-30 12:06:16

设计模式之代理模式(3)的相关文章

Android设计模式之代理模式 Proxy

一.概述 代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A坐享中介筛选的结果,并且交房租也是交给中介,这就是一个典型的日常生活中代理模式的应用.平时打开网页,最先开到的一般都是文字,而图片等一些大的资源都会延迟加载,这里也是使用了代理模式. 代理模式的组成: Abstract Subject:抽象主题-声明真实主题和代理主题共同的接口

【设计模式】代理模式

代理模式在所需对象和用户代码之间增加了一层对象,这个对象被称为代理.用户代码只需要直接操作代理对象即可.著名的代理模式的例子就是引用计数指针对象,它使得我们对真实对象的操作都需要经过引用计数指针对象.下面是用C++写的一个运用了代理模式的例子. #include <iostream> #include <string> using namespace std; // 作为接口的抽象基类 class Subject { public: virtual void DoAction()

设计模式之代理模式(Proxy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

【大话设计模式】——代理模式

对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念.Hibernate 的继承映射可以理解持久化类之间的继承关系.例如:人和学生之间的关系.学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到. Hibernate支持三种继承映射策略: 使用 subclass 进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态. 使用 joined-subclass 进行映射: 对于继承关系中的子类使用同一个表

设计模式之代理模式 c++实现以及详解

proxy模式 <1> 作用: 为其他对象提供一种代理以控制对这个对象的访问. <2> 代理模式的应用场景: 如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1.修改原有的方法来适应.这样违反了"对扩展开放,对修改关闭"的原则. 2.就是采用一个代理类调用原有的方法,且对产生的结果进行控制.这种方法就是代理模式. 使用代理模式,可以将功能划分的更加清晰,有助于后期维护! <3> 结构图 代理类,含有一个指向RealSubject

JAVA设计模式之代理模式

学编程吧JAVA设计模式之代理模式发布了,欢迎通过xuebiancheng8.com来访问 一.概述 给某一个对象提供一个代理,并由代理对象来完成对原对象的访问.代理模式是一种对象结构型模式. 二.适用场景 当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口. 三.UML类图 四.参与者 1.接口类:Subject 它声明了真实访问者和代理访问者的共同接口,客户端通常需要针对接口角色进行编程. 2.代理类

JAVA设计模式(3)----代理模式

1.  什么是代理模式?Proxy Pattern 代理模式定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 通俗的讲,代理模式就是我很忙没空理你,你要想找我可以先找我的代理人,代理人和被代理人继承同一个接口.代理人虽然不能干活,但是被代理的人可以干活. 这个例子中有水浒传中的这么几个人:名垂青史的潘金莲,王婆,西门大官人.西门庆想要找潘金莲,需要找王婆做代理.首先定义一个接口:Kin

设计模式之代理模式20170724

结构型设计模式之代理模式: 一.含义 代理模式也叫做委托模式,其定义如下: 为其他对象提供一种代理以控制对这个对象的访问. 二.代码说明 1.主要有两个角色 1)具体主题角色 也叫做委托角色.被代理角色.它是业务逻辑的具体执行者. 2)代理主题角色 也叫做委托类.代理类.它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作. 一个代理类可以代理多个被委托者或被代理者. 2.在用C实现过程中也是参考这种思想,以游戏代理场

设计模式 11 —— 代理模式

设计模式目录: 设计模式 1 ——观察者模式 设计模式 2 —— 装饰者模式 设计模式 3 —— 迭代器和组合模式(迭代器) 设计模式 4 —— 迭代器和组合模式(组合) 设计模式 5 —— 工厂模式 设计模式 6 —— 单件模式 设计模式 7 —— 命令模式 设计模式 8 —— 适配器和外观模式 设计模式 9 —— 模板方法模式 设计模式 10 —— 状态模式 设计模式 11 —— 代理模式 概述 一 代理模式基本概念 二 参考 一 代理模式基本概念 代理模式为另一个对象提供一个替身或占位符以

跟我学设计模式视频教程——代理模式

课程视频 代理模式1 代理模式2 课程笔记 课程笔记 课程代码 课程代码 新课程火热报名中 课程介绍 跟我学设计模式视频教程--代理模式