浅谈代理Proxy

来源:互联网 发布:营销软件官网 编辑:程序博客网 时间:2024/05/17 04:01
代理Proxy分为静态代理,JDK动态代理,CGLib动态代理。
首先来个最原始的Hello接口
public interface Hello {
     void say(String name);
}
接着提供它的实现类
public class HelloImpl implements Hello {
     @Override
     public void say(String name) {
           System.out.println("Hello!" + name);
     }
}
静态代理
静态代理一般实现需要代理的接口。
public class HelloProxy implements Hello {
     private HelloImpl helloImpl;

     public HelloProxy() {
           helloImpl = new HelloImpl();
     }

     @Override
     public void say(String name) {
           before();
           helloImpl.say(name);
           after();
     }

     private void before() {
           System.out.println("START");
     }

     private void after() {
           System.out.println("END");
     }

}
测试类
@Test
public void testHelloProxy() {
     Hello hello = new HelloProxy();
     hello.say("小明");
}
由此可以看出,静态代理会产生很多 XxxProxy类。
JDK动态代理
由于静态会产生一堆的XxxProxy类,不得已,我们的动态代理就出现了。
public class DynamicProxy implements InvocationHandler {
     private Object target;

     public DynamicProxy(Object target) {
           this.target = target;
     }

     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           before();
           Object result = method.invoke(target, args);
           after();
           return result;
     }

     @SuppressWarnings("unchecked")
     public <T> T getProxy() {
           return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
     }

     private void before() {
           System.out.println("START");
     }

     private void after() {
           System.out.println("END");
     }
}
在DynamicProxy类中,实现了InvocationHandler接口,实现接口的invoke方法。同时定义了一个target变量,它就是被代理的目标对象,通过构造函数来初始化。
测试类
@Test
     public void testDynamicProxyTwo() {
           Hello hello = new HelloImpl();
           DynamicProxy dynamicProxy = new DynamicProxy(hello);
           Hello helloProxy = dynamicProxy.getProxy();
           helloProxy.say("小平");
     }
利用JDK动态代理成功解决了产生多个XxxProxy类的弊端,但是好像只能代理接口,如果代理的是类怎么办呢?接下来就是CGLib动态代理来解决这个问题吧
CGLib动态代理
CGLib (Code Generation Library) 是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO字节码的动态生成。CGLib 比 Java 的 java.lang.reflect.Proxy 类更强的在于它不仅可以接管接口类的方法,还可以接管普通类的方法。
public class CGLibProxy implements MethodInterceptor {
     private static CGLibProxy instance = new CGLibProxy();

    public static CGLibProxy getInstance() {
        return instance;
    }

     @SuppressWarnings("unchecked")
     public <T> T getProxy(Class<T> cls) {
        return (T) Enhancer.create(cls, this);
    }

     @Override
     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
           before();
           Object result = proxy.invokeSuper(obj, args);
           after();
           return result;
     }

     private void before() {
           System.out.println("START");
     }

     private void after() {
           System.out.println("END");
     }
}
需要实现 CGLib 给我们提供的 MethodInterceptor 接口,实现 intercept() 方法。
参数:obj为由CGLib动态生成的代理类实例,method为上文中实体类所调用的被代理的方法引用,args为参数值列表,proxy为生成的代理类对方法的代理引用。
返回:从代理实例的方法调用返回的值。
其中,proxy.invokeSuper(obj, args):执行原始类的方法
CGLib 给我们提供的是方法级别的代理,也可以理解为对方法的拦截。
测试类
@Test
     public void testCGLibProxy() {
           HelloImpl helloImpl = CGLibProxy.getInstance().getProxy(HelloImpl.class);
         helloImpl.say("小张");
     }