首页 > 代码库 > 动态代理
动态代理
上次总结了一下静态代理,代理的思想很容易理解,但是静态代理的能力毕竟有限。假如我有很多类都需要使用相同的代理,那么我们必须为其编写代理类,而这些代理类做的工作大都一样,在关键时刻会调用真实对象,在调用真实对象的方法前后会有所增强处理。不同之处就是调用的对象不同,那么是否有这样一个类,只需我们给它一个真实对象,给它一些必要的参数,它就能帮我们生成代理类呢。
当然可以,JDK自带的就有,它们就是java.lang.reflect包中的InvocationHandler接口和Proxy类,这种动态代理依赖于接口。还有一种是cglib的动态代理,它不需要实现特定的接口,基于字节码技术实现。
一.JDK动态代理
还是上次的接口和真实对象:
//专业迎宾团队 public interface IHelloWorld { //规定了做什么 public void sayhello(); }
//第二小队 public class HelloWorldImpl2 implements IHelloWorld { //同样是致欢迎 用标准普通话 @Override public void sayhello() { System.out.println("您好 !"); } }
创建一个自己的调用处理器,实现InvocationHandler接口:
/** * @author Lucare * JDK动态代理 * 2014年12月16日 */ //自定义调用处理器 public class MyInvocationHandler implements InvocationHandler{ //使用了Object类型 可代理的类更多 private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("doSomething before the method"); Object result = method.invoke(target, args); System.out.println("doSomething after the method"); return result; } /** * 获取代理类的实例 实际上是jdk动态帮我们生成了一个子类 该类继承了委托类 * 然后对其进行了扩展,加入了委托类实际方法前后的处理,运用反射来完成这一扩展 */ public Object getProxy(){ return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); } }
客户端测试:
public class Client { public static void main(String[] args) { IHelloWorld helloword = new HelloWorldImpl2(); MyInvocationHandler mih = new MyInvocationHandler(helloword); IHelloWorld proxy = (IHelloWorld) mih.getProxy(); proxy.sayhello(); } }输出:
doSomething before the method 您好 ! doSomething after the method
刚开始我也会好奇:那个接口中的invoke方法被谁调用?当我们获得了代理类的实例proxy,它实现了IHelloWord接口,必然也实现了接口中的sayhello方法,而我们并没有明显调用invoke方法,那么只可能是在sayhello方法中被调用。
现在假如我们需要再使用代理,我们要更改的只是Client类的代码,或者我们在另一个地方直接重新来个Client,只要和前面的相关,再来一个真实类。也可以再重新定义一个接口,再来若干实现。总之代码可以最大限度得到复用,我们可以共用调用处理器前后的增强。
二.Cglib动态代理
这个例子需要下载相关jar包。在这里我也只是简单了解了下,但是在框架中得到了很多运用,因为这种方式可以达到非侵入式的效果,你只需要写好真实类,它会帮你在合适的地方加入方法增强,如下所示。
一个真实类:
public class HelloWorld { public void sayhello(){ System.out.println("Hello world!"); } }
一个创建代理的类:
//使用第三方cglib的动态代理,基于字节码实现,拦截实际方法 public class CglibProxy implements MethodInterceptor{ //要代理的原始对象 private Object obj; public Object createProxy(Object target){ this.obj = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.obj.getClass());//设置代理目标 enhancer.setCallback(this);//设置回调 // enhancer.setClassLoader(target.getClass().getClassLoader()); //通过字节码技术动态创建子类实例 return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable { Object result = null; System.out.println("before this method invoke"); //调用原始对象的方法 result = methodProxy.invokeSuper(proxy, params); System.out.println("after this method invoke"); return result; } }
测试客户端:
package com.fcs.cglib; public class Client { public static void main(String[] args) { HelloWorld helloworld = new HelloWorld(); CglibProxy cglibProxy = new CglibProxy(); HelloWorld hw = (HelloWorld) cglibProxy.createProxy(helloworld); hw.sayhello(); } }
输出:
before this method invoke Hello world! after this method invoke
是不是感觉清爽了很多,是不是有了春天(spring)的感觉。任何类都可以使用这个代理了,只要它是我们需要的,我们就把真实对象传给这个代理生成类的createProxy方法,然后一切高枕无忧,生成的代理类就是真实类的子类,方法sayhello得到了重写,我们向上转型,然后调用sayhello。
不足之处敬请指正。
动态代理