代理

100 阅读2分钟

静态代理

和代理设计模式比较接近, 写一个类, 将一个类, 或一个借口当做成员属性, 在增强的代码块中执行被代理类的方法即可.

缺点: 需要针对不同的被代理类编写不同的代理类.

动态代理

不用手写定义, 由虚拟机在运行时, 根据配置规则, 在环境中生成Class类, 来生成实例对象.

动态代理有两种方式, 一个是JDK的动态代理, 一个是cglib.

由于提倡的是面向接口编程, 因此jdk动态代理是针对接口实现类的代理, 代理类可以实现接口的各种实现, 比较符合抽象编码规则. 

cglib则是会生成代理对象的继承类, 起到能够代理所有的方法的作用.

jdk动态代理

JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,这两个类相互配合,入口是Proxy.

Proxy.getProxyClass()会根据接口的Class, 获取一个代理类的Class. 

接口是没有构造器的, 但是代理类是有的, 还是有参的构造器.
Class animalClazz = Proxy.getProxyClass(Animal.class.getClassLoader(), Animal.class);
System.out.println(animalClazz.getName());
System.out.println(Animal.class.getName());
接下来就是获取构造器, jdk提供了含参构造器, 参数是InvocationHandler. 它是代理类的一个属性, 会作为中介, 调用被代理类的方法.

InvocationHandler的invoke方法的结果,  会代替代理目标的方法.
Constructor constructor = animalClazz.getConstructor(InvocationHandler.class);
        Animal animal = (Animal) constructor.newInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("method start...");
                // 执行具体的业务逻辑
                Object object = method.invoke(target, args);
                System.out.println("method end...");
                return object;
            }
        });
        return animal;
不过实际编程中,一般不用getProxyClass(),而是使用Proxy类的另一个静态方法:Proxy.newProxyInstance(),直接返回代理实例
Object proxy = Proxy.newProxyInstance(
              target.getClass().getClassLoader(),/*类加载器*/
              target.getClass().getInterfaces(),/*让代理对象和目标对象实现相同接口*/
              new InvocationHandler(){/*代理对象的方法最终都会被JVM导向它的invoke方法*/
           @Override
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                 System.out.println(method.getName() + "method start...");
                 Object result = method.invoke(target, args);
                 System.out.println(result);
                 System.out.println(method.getName() + "method end...");
                 return result;
             }
          }
    );
return proxy;
可以输出代理类的代码来看看
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Animal.class});
FileOutputStream fileInputStream = new FileOutputStream("hello.class");
fileInputStream.write(bytes);
fileInputStream.flush();
fileInputStream.close();
System.out.println("完毕");