动态代理的原理是什么?
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可以克服对接口的依赖。