java动态代理原理及简单模拟

为跳槽做打算,最近在猛学,回顾一下知识点,突然发现动态代理还是理解的模糊,狠狠研究了一天,写此文以作纪念。
首先写个普通的代理

来个接口:

public interface Drawable {

public void draw();

}

再来个实现类:

public class Pen implements Drawable {

public void draw() {
System.out.println("draw something");
}

}


代理类(随便在博客写,未经编译):

public class ProxyPen implements Drawable{
private Drawable draw;
public ProxyPen(Drawable draw){
this.draw = draw;
}
public viod draw(){
System.out.println("before draw");
draw.draw();
}
}
//接下来为调用代码
Drawable pen = new Pen();
ProxyPen proxy = new ProxyPen(pen);
proxy.draw();

以上的静态代理很简单,无非就是聚合+多态。
但是只能代理实现Drawable接口的类,显然具有很大局限性。
而动态代理顾名思义就是动态生成代理类,ProxyPen将根据参数动态生成,要让其动态生成显然必须取得代理的接口,取得接口后能实现代理类,但是代理类添加的内容却还是定死的System.out.println("before draw");这也不满足动态要求,所以代理内容必须也要能自定义,想输任何代理内容,当然还是多态,传入一个处理代理内容的接口Handler即可:
首先定义代理接口:

public interface InvocationHandler {
public void invoke(Method m,Object... args) throws Exception;
}


public class Proxy {

public static Object newProxy(Class interfaces,InvocationHandler handler) throws Exception{
String r = "\n";

Method[] methods = interfaces.getMethods();

StringBuffer sb = new StringBuffer("");

for(int i =0;i<methods.length;i++){
sb.append(" public void "+methods[i].getName()+"() {"+r+
" try{ "+r+
" Method md = "+interfaces.getName()+".class.getMethod(\""+methods[i].getName()+"\");"+r+
" handler.invoke( md,new Object[]{});"+r+
" }catch(Exception e){e.printStackTrace();}"+r+
" }"+r
);
}

String src = "package com.javaeye.aronlulu.proxy;"+r+
"import java.lang.reflect.*;"+r+
"public class ProxyPen implements "+interfaces.getName() +"{"+r+

" private com.javaeye.aronlulu.proxy.InvocationHandler handler;"+r+

" public ProxyPen("+handler.getClass().getName()+" handler){"+r+
" this.handler = handler;"+r+
" }"+r+
System.out.println(\"before\");"+r+

sb.toString()+

"}" +r;
String dir = System.getProperty("user.dir")+"/src/com/javaeye/aronlulu/proxy/";
FileWriter writer = new FileWriter(new File(dir+"ProxyPen.java"));
writer.write(src);
writer.flush();
writer.close();
//编译动态代理类
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(dir+"ProxyPen.java");
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
//加载并调用返回代理接口
URL[] urls = new URL[]{new URL("file:/"+dir)};
URLClassLoader loader = new URLClassLoader(urls);
Class c = loader.loadClass("com.javaeye.aronlulu.proxy.ProxyPen");

Constructor ctr = c.getConstructor(handler.getClass());
return ctr.newInstance(handler);

}

}


接下来编写具体处理代理类代码:

public class DrawHandler implements InvocationHandler {

private Object draw;

public DrawHandler (Object draw){
this.draw = draw;
}

public void invoke(Method m,Object[] args) throws Exception{
System.out.println("before");
m.invoke(draw, args);
System.out.println("after");
}

}

测试代码:

Drawable drawable = new Pen();
InvocationHandler handler = new DrawHandler(drawable);
Drawable draw = (Drawable) Proxy.newProxy(Drawable.class,handler);
draw.draw();

动态代理的实现简单完成了,当然跟java的动态代理实现没法比,中间还封装了很多类型检查及反射实现。动态代理原理其实无非就是反射+多态+聚合的实现,当然有了动态代理,很多强大的功能就能实现了,最有名的无非就是AOP,java动态代理的局限性是只能针对接口,若要针对具体业务类,则需要CGLIB这样的第三方框架了,springAOP则采用了以上两种组合,默认还是使用java动态代理,设置Bean中一个属性开关来控制,若非接口实现,则开始调用CGLIB。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值