动态代理

看了马士兵老师对动态代理的讲解,然后这篇博客主要对视频内容的一个总结,以及一些自己的理解。
首先从抛出这样一个问题作为引入:计算一个方法的运行时间(我们想到的一般的方法就是利用聚合或者是继承,就聚合和继承来说,聚合要好于继承,因为多种代理的叠加的时候就会非常不灵活)
接下来来实现对方法运行时间的计算,创建Moveable接口,声明一个方法move()

public interface Moveable {

void move();

}

Tank类实现了Moverable接

public class Tank implements Moveable {

@Override
public void move() {

System.out.println("Tank Moving...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}

}

生成Tank的代理类TankTimeProxy,用来计算其move方法运行时间,该代理类也实现了Moveable接口

public class TankTimeProxy implements  Moveable {

public TankTimeProxy(Moveable m) {

this.m = m;

}



Moveable m;

@Override

public void move() {

Long start=System.currentTimeMillis();

m.move();

Long end=System.currentTimeMillis();

System.out.println(end-start);

}

}

运行move方法

public class testTank {

public static void main(String[] args) {

Tank t=new Tank();

//        TankLogProxy tlp=new TankLogProxy(t);

TankTimeProxy ttp=new TankTimeProxy(t);

Moveable m=ttp;

m.move();



}

结果展示:

Tank Moving...

4165

根据接口来生成代理类,要求被代理的类都实现某个接口,但是这样只能静态的生成实现了特定接口的代理,而不能为任何对象任何类动态生成代理,然后下面继续修改代码:

创建proxy类,创建一个静态的 newProxyInstance(Class infce,InvocationHandler h)来产生新的代理类,参数infce指代对哪个接口来产生代理,参数h表示产生的是什么类型的代理(也就是指定的处理方式)。
基本思想就是在newProxyInstance()方法中动态生成代理类的代码,然后进行编译,然后再将编译后的文件load到内存,利用反射生成类对象,并返回代理对象;具体代码如下:

InvocationHandler接口:

public interface InvocationHandler {
public void invoke(Object o, Method m);        //要对哪个代理对象调用哪个方法
}

实现一个计算方法运行时间的handler:

public class TimeHandler implements InvocationHandler{

private Object target;   //对哪个对象进行代理(也就是目标代理对象)



public TimeHandler(Object target) {       //构造方法
super();
this.target = target;
}



@Override
public void invoke(Object o, Method m) {     //调用被代理对象o的m方法
long start = System.currentTimeMillis();   //具体代理逻辑
System.out.println("starttime:" + start);
System.out.println(o.getClass().getName());
try {
m.invoke(target);    //调用被代理对象的方法
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("time:" + (end-start));
}

}

Proxy类代码:

public class Proxy {
public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception { //JDK6 Complier API, CGLib, ASM    infce表示对哪个接口产生动态代理  h表示产生的是什么类型的代理(指定的处理方式)
String methodStr = "";
String rt = "\r\n";

Method[] methods = infce.getMethods();
/*
for(Method m : methods) {
methodStr += "@Override" + rt +
"public void " + m.getName() + "() {" + rt +
"   long start = System.currentTimeMillis();" + rt +
"   System.out.println(\"starttime:\" + start);" + rt +                 //这样不能灵活的指定代理的内容
"   t." + m.getName() + "();" + rt +
"   long end = System.currentTimeMillis();" + rt +
"   System.out.println(\"time:\" + (end-start));" + rt +
"}";
}
*/
for(Method m : methods) {
methodStr += "@Override" + rt +
"public void " + m.getName() + "() {" + rt +
"    try {" + rt +
"    Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
"    h.invoke(this, md);" + rt +
"    }catch(Exception e) {e.printStackTrace();}" + rt +

"}";
}

String src =
"package com.bjsxt.proxy;" +  rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy1 implements " + infce.getName() + "{" + rt +
"    public $Proxy1(InvocationHandler h) {" + rt +
"        this.h = h;" + rt +
"    }" + rt +


"    com.bjsxt.proxy.InvocationHandler h;" + rt +

methodStr +
"}";
String fileName =
"d:/test/com/bjsxt/proxy/$Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();

//compile
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);  //管理文件
Iterable units = fileMgr.getJavaFileObjects(fileName); //获取java文件对象。可以多个
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:/" + "d:/test/")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1");
System.out.println(c);

Constructor ctr = c.getConstructor(InvocationHandler.class);    //根据方法的参数去获取构造方法
Object m = ctr.newInstance(h);      //生成对象,调用代理类的构造方法,将具体的handle传入
//m.move();

return m;      //返回代理对象
}
}

测试产生代理对象:

public class Client {
public static void main(String[] args) throws Exception {

Moveable m = new Tank();
InvocationHandler h = new TimeHandler(m);     //把要被代理的接口传给handler
Moveable u = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
u.move();     //调用代理类的方法
}
}

这样Proxy的newProxyInstance方法实现了动态编译(spring用了CGLIB),动态生成代理对象(不用知道代理类的名字是什么)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值