Java代理
其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该 地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有 专长,可以替我们进行操作,表达我们的想法。先来看看关系图:
代理模式的应用场景: 如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1、修改原有的方法来适应。这样违反了"对扩展开放,对修改关闭"的原则。 2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。 使用代理模式,可以将功能划分的更加清晰,有助于后期维护! |
普通代理模式事例: |
Moveable.java |
package proxy;
public interface Moveable { void move();
} |
Tank.java |
//Tank实现Moveable方法 public class Tank implements Moveable { @Override public void move() { System.out.println("Tank Moving...");}} |
Client.java |
package proxy; public class Client { public static void main(String[] args) throws Exception { Tank t = new Tank(); InvocationHandler h = new TimeHandler(t); Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h); m.move();}} //可以对任意的对象、任意的接口方法,实现任意的代理 |
动态代理的设计原理: |
客户端调用代理,代理的构造方法接收一个Handler对象,客户端调用代理的各个方法时,代理的相应方法会把调用请求转发给Handler对象,Handler对象又把请求分发给目标的响应方法。 |
InvocationHandler.java |
package proxy;
import java.lang.reflect.Method;
public interface InvocationHandler { public void invoke(Object o, Method m); } |
Proxy.java |
public class Proxy { public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception { //JDK6 Complier API, CGLib, ASM String methodStr = ""; String rt = "\r\n";//wimdows中的换行符。
Method[] methods = infce.getMethods(); 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 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 +
" proxy.InvocationHandler h;" + rt +
methodStr + "}"; String fileName = "D:/workspace4java/MyJavaDesign/src/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); 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:/workspace4java/MyJavaDesign/src/")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("proxy.$Proxy1"); System.out.println(c);
Constructor ctr = c.getConstructor(InvocationHandler.class); Object m = ctr.newInstance(h); //m.move();
return m; } } |
TimeHandler.java |
public class TimeHandler implements InvocationHandler{ private Object target; public TimeHandler(Object target) { super(); this.target = target; } @Override public void invoke(Object o, Method m) { long start = System.currentTimeMillis(); System.out.println("starttime:" + start); System.out.println(o.getClass().getName()); m.invoke(target); long end = System.currentTimeMillis(); System.out.println("time:" + (end-start)); }
} |
Java的CGLib动态代理(这里没有代码需要自己动手)
CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。
public class BookFacadeImpl {
public void addBook() {
System.out.println("增加图书方法。。。");
}
}
CGLib动态代理
- /**
- * 使用cglib动态代理
- */
- public class BookFacadeCglib implements MethodInterceptor {
- private Object target;
- /**
- * 创建代理对象
- * @param target
- * @return
- */
- public Object getInstance(Object target) {
- this.target = target;
- Enhancer enhancer = new Enhancer();
- // 设置需要创建子类的类
- enhancer.setSuperclass(this.target.getClass());
- // 回调方法
- enhancer.setCallback(this);
- // 通过字节码技术动态创建子类实例
- return enhancer.create();
- }
- @Override
- // 回调方法 ,拦截所有的父类方法调用
- public Object intercept(Object obj, Method method, Object[] args,
- MethodProxy proxy) throws Throwable {
- System.out.println("事物开始");
- Object result = proxy.invokeSuper(obj, args); // 通过代码类调用父类中的方法
- System.out.println("事物结束");
- return result;
- }
- }
BookFacadeCglib cglib=new BookFacadeCglib();
BookFacadeImpl bookCglib=(BookFacadeImpl)cglib.getInstance(new BookFacadeImpl());
bookCglib.addBook();
最终运行的结果如下:
事物开始
增加图书方法。。。
事物结束
☞注:加入cglib和asm的jar包。CGGlib创建的代理对象要比JDK的性能高很多,但是创建时所花费的时间却比JDK动态代理要多。所以对于singleton的代理对象或者具有实例池的代码,由于无须频繁创建代码对象,用CGLib比较合适。
也就是生命周期长的实例用CGLib比较合适。