代理模式及JDK动态代理(InvocationHandler)的简单实现与分析
在慕课网上学习了讲解代理模式的一个课程--《模式的秘密--代理模式》,感叹于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 {
-
-
public void buyIt() {
-
System.out.println("This computer is from HangKang!");
-
}
-
}
-
//代理对象角色
-
class ProxyMacBook implements IMacBook {
-
-
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 {
-
-
-
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 方法的返回值
-
* */
-
-
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 {
-
-
-
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 {
-
-
-
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;
-
}
-
-
-
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;
-
-
public void move() {
-
try{
-
Method md = com.mhb.proxy.Moveable.class.getMethod("move");
-
h.invoke(this,md);
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
}
运行结果:
汽车开始行驶....
汽车行驶中....
汽车结束行驶.... 汽车行驶时间:830毫秒!

浙公网安备 33010602011771号