为跳槽做打算,最近在猛学,回顾一下知识点,突然发现动态代理还是理解的模糊,狠狠研究了一天,写此文以作纪念。
首先写个普通的代理
来个接口:
再来个实现类:
代理类(随便在博客写,未经编译):
以上的静态代理很简单,无非就是聚合+多态。
但是只能代理实现Drawable接口的类,显然具有很大局限性。
而动态代理顾名思义就是动态生成代理类,ProxyPen将根据参数动态生成,要让其动态生成显然必须取得代理的接口,取得接口后能实现代理类,但是代理类添加的内容却还是定死的System.out.println("before draw");这也不满足动态要求,所以代理内容必须也要能自定义,想输任何代理内容,当然还是多态,传入一个处理代理内容的接口Handler即可:
首先定义代理接口:
接下来编写具体处理代理类代码:
测试代码:
动态代理的实现简单完成了,当然跟java的动态代理实现没法比,中间还封装了很多类型检查及反射实现。动态代理原理其实无非就是反射+多态+聚合的实现,当然有了动态代理,很多强大的功能就能实现了,最有名的无非就是AOP,java动态代理的局限性是只能针对接口,若要针对具体业务类,则需要CGLIB这样的第三方框架了,springAOP则采用了以上两种组合,默认还是使用java动态代理,设置Bean中一个属性开关来控制,若非接口实现,则开始调用CGLIB。
首先写个普通的代理
来个接口:
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。