动态代理的原理是什么?

JDK动态代理

下面可以看看JDK动态代理的一个简单的例子,下面只是加了一句print,在生产系统中,我们可以轻松扩展类似逻辑进行诊断、限流等。

  • 接口Hello
public interface Hello{
    void sayHello();
}
  • 接口的实现类HelloImpl
public class HelloImpl implements Hello {

    @Override
    public void sayHello() {
        System.out.println("Hello JDK Dynamic Proxy!!!");
    }
}
  • DynamicProxyMain类
public class DynamicProxyMain {

    public static void main(String[] args) {
        HelloImpl hello = new HelloImpl();
        JDKDynamicProxy handler = new JDKDynamicProxy(hello);

        //构造代码实例
        Hello proxyHello = new JDKDynamicProxy(new HelloImpl()).getProxy();
        //使用代理对象调用代理方法
        proxyHello.sayHello();
    }

    /**
     * 创建一个代理类JDKDynamicProxy实现java.lang.reflect.InvocationHandler接口,重写invoke方法
     */
    static class JDKDynamicProxy implements InvocationHandler{

        private Object target;
        public JDKDynamicProxy(Object target) {
            this.target = target;
        }

        /**
         * 获取被代理接口实例对象
         * @param <T>
         * @return
         */
        public <T> T getProxy() {
            return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("正在代理sayHello方法......");
            Object result = method.invoke(target, args);
            return result;
        }
    }
}

运行main函数,结果如下:

正在代理sayHello方法......
Hello JDK Dynamic Proxy!!!
  • 上面的JDK Proxy例子,非常简单地实现了动态代理的构建和代理操作。首先,我们自定义对应的 JDKDynamicProxy ;然后,以接口Hello为纽带,为被调用目标创建代理对象,进而应用程序就可以使用代理对象间接运行调用目标的逻辑,代理为应用插入额外逻辑(这里仅仅提供println方法)提供了入口。
  • 不过,JDK动态代理也有一定局限性,因为必须是以接口为中心,相当于添 加了一种对于被调用者没有太大意义的限制。我们实例化的是 Proxy 对象,而不是真正的 被调用类型,这在实践中还是可能带来各种不便和能力退化。
  • 如果被调用者每月实现接口,而我们有希望使用动态代理机制,那么就可以考虑使用其他的方式,比如:Spring AOP支持两种模式的动态代理,JDK Proxy和cglib,选择cglib可以克服对接口的依赖。
10-22 12:14