代理模式及JDK动态代理(InvocationHandler)的简单实现与分析

原创 2016年08月28日 22:24:30

在慕课网上学习了讲解代理模式的一个课程--《模式的秘密--代理模式》,感叹于David老师屌炸天的PPT,同时,老师一步一步模仿JDK源码去写code,教我们去简单实现JDK中的动态代理,讲的清晰透彻。在此我做下笔记,课程原地址:http://www.imooc.com/learn/214

一、概述

代理模式定义:为其他对象提供一种代理,以控制对这个对象的访问。代理对象起到中介作用,可以去掉功能服务或增加额外的服务。

常见的代理模式:

(1)远程代理:给一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又称为大使(Ambassador)。

(2)虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。e.g. 刷网页,先显示预先准备好的背景图,等真正的图片加载完成后再显示。

(3)保护代理:控制用户的访问权限

(4)智能引用代理:提供对目标对象额外的服务

代理的实现方式:静态代理、动态代理


二、静态代理

代理和被代理对象在代理之前是确定的,他们都实现相同的接口或者继承相同的抽象类。类图如下:


举例如下:

package com.test.proxytest;

//抽象对象角色
interface IMacBook {
    void buyIt();
}
//目标对象角色
class HangKangMacBook implements IMacBook {
    @Override
    public void buyIt() {
        System.out.println("This computer is from HangKang!");
    }
}
//代理对象角色
class ProxyMacBook implements IMacBook {
    @Override
    public void buyIt() {
        HangKangMacBook mac = new HangKangMacBook();
        mac.buyIt();
    }
}
//客户端
public class Main {
    public static void main(String[] args) {
        IMacBook macBook = new ProxyMacBook();
        macBook.buyIt();
    }
}

三、JDK动态代理

Java动态代理位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)Interface InvocationHandler

该接口中仅定义了一个方法:public Object invoke(Object obj, Method method, Object[] args),在使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy

该类即为动态代理类,static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h),返回代理类的一个实例,返回后的代理类可以当作被代理类使用。


JDK动态代理的一般实现步骤如下:

(1)创建一个实现InvocationHandler接口的类,它必须实现invoke方法

(2)创建被代理的类以及接口

(3)调用Proxy的静态方法newProxyInstance,创建一个代理类

(4)通过代理调用方法

举例如下:

public interface Moveable {
	void move();
}
public class Car implements Moveable {

	@Override
	public void move() {
		//实现开车
		try {
			Thread.sleep(new Random().nextInt(1000));
			System.out.println("汽车行驶中....");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
public class TimeHandler implements InvocationHandler {

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

	private Object target;
	
	/*
	 * 参数:
	 * proxy  被代理对象
	 * method  被代理对象的方法
	 * args 方法的参数
	 * 
	 * 返回值:
	 * Object  方法的返回值
	 * */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		long starttime = System.currentTimeMillis();
		System.out.println("汽车开始行驶....");
		method.invoke(target);
		long endtime = System.currentTimeMillis();
		System.out.println("汽车结束行驶....  汽车行驶时间:" 
				+ (endtime - starttime) + "毫秒!");
		return null;
	}

}
public class Test {

	/**
	 * JDK动态代理测试类
	 */
	public static void main(String[] args) {
		Car car = new Car();
		InvocationHandler h = new TimeHandler(car);
		Class<?> cls = car.getClass();
		/**
		 * loader  类加载器
		 * interfaces  实现接口
		 * h InvocationHandler
		 */
		Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),
												cls.getInterfaces(), h);
		m.move();
	}

}

运行结果如下:



四、JDK动态代理的简易实现

动态代理的实现思路

实现功能:通过Proxy的newProxyInstance返回代理对象

(1)声明一段源码(动态产生代理)

(2)编译源码(JDK Compiler API),产生新的类(代理类)

(3)将这个类load到内存当中,产生一个新的对象(代理对象)

(4)return代理对象

package com.mhb.proxy;

public interface Moveable {
    void move();
}
package com.mhb.proxy;

import java.util.Random;

public class Car implements Moveable {

    @Override
    public void move() {
        //实现开车
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽车行驶中....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
package com.mhb.proxy;

import org.apache.commons.io.FileUtils;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Proxy {

    @SuppressWarnings("unchecked")
    public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
        String rt = "\n";
        String rx = "    ";
        String methodStr = "";
        for(Method m : infce.getMethods()){
            methodStr +=
                    "@Override" + rt + rx +
                    "public void " + m.getName() + "() {" + rt + rx +
                    "    try{" + rt + rx +
                    "        Method md = " + infce.getName() + ".class.getMethod(\""+ m.getName() + "\");" + rt + rx +
                    "        h.invoke(this,md);" + rt + rx +
                    "    } catch (Exception e) { " + rt + rx +
                    "        e.printStackTrace();" + rt + rx +
                    "    }" + rt + rx +
                    "}" ;
        }

        String str =
                "package com.mhb.proxy;" + rt +
                "import java.lang.reflect.Method;" + rt +
                "import com.mhb.proxy.InvocationHandler;" +  rt+
                "public class $Proxy0 implements " + infce.getName() + " {" + rt +
                "    public $Proxy0(InvocationHandler h) {" + rt +
                "        this.h = h;" + rt +
                "    }" + rt +
                "    private InvocationHandler h;" + rt+
                "    " + methodStr + rt +
                "}" ;
        //产生代理类的java文件
        String filename = System.getProperty("user.dir") +"/bin/com/mhb/proxy/$Proxy0.java";
        File file = new File(filename);
        FileUtils.writeStringToFile(file, str);

        //编译
        //拿到编译器
        JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
        //文件管理者
        StandardJavaFileManager fileMgr =
                complier.getStandardFileManager(null, null, null);
        //获取文件
        Iterable units = fileMgr.getJavaFileObjects(filename);
        //编译任务
        CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
        //进行编译
        t.call();
        fileMgr.close();

        //load到内存
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        Class c = cl.loadClass("com.mhb.proxy.$Proxy0");

        Constructor ctr = c.getConstructor(InvocationHandler.class);
        return ctr.newInstance(h);
    }
}
package com.mhb.proxy;

import java.lang.reflect.Method;

public interface InvocationHandler {

    void invoke(Object o,Method m);
}
package com.mhb.proxy;

import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler {

    private Object target;

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

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

        try {
            long starttime = System.currentTimeMillis();
            System.out.println("汽车开始行驶....");
            m.invoke(target);
            long endtime = System.currentTimeMillis();
            System.out.println("汽车结束行驶....  汽车行驶时间:"
                    + (endtime - starttime) + "毫秒!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.mhb.proxy;

public class Client {

    /**
     * 测试类
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        Car car = new Car();
        InvocationHandler h = new TimeHandler(car);
        Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);
        m.move();
    }
}

IntelliJ IDEA目录结构(bin目录需要设为Resources Root):


生成的$Proxy0.java如下:

package com.mhb.proxy;
import java.lang.reflect.Method;
import com.mhb.proxy.InvocationHandler;
public class $Proxy0 implements com.mhb.proxy.Moveable {
    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }
    private InvocationHandler h;
    @Override
    public void move() {
        try{
            Method md = com.mhb.proxy.Moveable.class.getMethod("move");
            h.invoke(this,md);
        } catch (Exception e) { 
            e.printStackTrace();
        }
    }
}


运行结果:

汽车开始行驶....
汽车行驶中....
汽车结束行驶....  汽车行驶时间:830毫秒!







版权声明:本文为博主原创文章,转载请注明来自 http://blog.csdn.net/hello2mao

相关文章推荐

关于java动态代理模式

1. 动态代理 动态代理就是通过代理类是代理类与相关接口不直接发生联系,而在运行期(Runtime)实现动态关联。动态代理主要用到java.lang.reflect包中的两个类,Invoca...
  • jzman
  • jzman
  • 2016-06-05 00:18
  • 1247

Java动态代理模式jdk和cglib的2种实现以及二者的区别(AOP面向切面的前奏)

关于动态代理模式里面有两种实现,一种是jdk实现,一种是cglib来实现。 下面来整jdk来实现动态代理的Java实例。 jdk动态代理模式里面有个拦截器的概念,在jdk中,只要实现了Invocati...

JDK使用InvocationHandler和Proxy实现动态代理

--------------------------------------------------实现InvocationHandler接口-----------------------------...

仿JDK的动态代理模式

代理模式 : 给某一对象提供代理对象,并由代理对象控制具体对象的引用. 一、代理模式涉及的角色: (1)抽象主题角色:声明了代理主题和真实主题的公共接口,使任何需要真实主题的地方都能用代理主题代替...

jdk动态代理模式的原理解析

近期一直在学习Mybatis,接触到了拦截器,接口式编程的知识,通过mybatis的学习,对于动态代理和责任链模式有了新的理解,所以决定写些文章以加深自己的印象。 这篇文章中先记录一下我理解的java...

关于java中jdk中接口动态代理模式Proxy的剖析

这个示例将展示jdk创建代理对象、调用实际对象、实际对象处理的整个过程,首先jdk动态代理只是针对接口而言的,即根据用户提供的接口创建一个实现接口的代理类并且把用户传入的实际对象作为代理对象的属性,当...

代理模式(五)JDK动态代理深入分析

原文出处:http://blog.csdn.net/mark_lq/article/details/48178497 JDK动态代理实现的核心技术是java反射机制,其主要的两个类是:Proxy、I...

代理模式(五)JDK动态代理深入分析

JDK动态代理实现的核心技术是java反射机制,其主要的两个类是:Proxy、InvocationHandler。使用java.lang.reflect.Proxy类可以动态实现接口作为代理类。 一....
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)