动态代理

什么是动态代理

它是一个代理机制。如果熟悉设计模式中的代理模式,我们会知 道,代理可以看作是对调用目标的一个包装,这样我们对目标代码的调 用不是直接发生的,而是通过代理完成。

通过代理可以让调用者与实现者之间解耦。比如进行RPC调用,框架内 部的寻址、序列化、反序列化等,对于调用者往往是没有太大意义的, 通过代理,可以提供更加友善的界面。

写一个简单的JDK动态代理例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class MyDynamicProxy {
public static void main(String[] args) {
HelloImpl helloImpl = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(helloImpl);
Hello hello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[]{Hello.class}, handler);
hello.hello();
}
}


interface Hello {
void hello();
}

class HelloImpl implements Hello {

@Override
public void hello() {
System.out.println("Hello World");
}
}

class MyInvocationHandler implements InvocationHandler {

//目标对象
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("前置通知代码");
//执行目标方法
Object result = method.invoke(target, args);
System.out.println("后置通知代码");
return result;
}
}

在上面的例子中,非常简单地实现了动态代理的构建和代理操作。首先,实现对应的InvocationHandler;然后,以接口Hello为纽带,为被调用目标构建代理对象,进而应用程序就可以使用代理对象间接运行调用目标的逻辑,代理为应用插入额外逻辑提供了便利的入口。

从API设计和实现的角度,这种实现仍然有局限性,因为它是以接口为 中心的,相当于添加了一种对于被调用者没有太大意义的限制。我们实 例化的是Proxy对象,而不是真正的被调用类型,这在实践中还是可能 带来各种不便和能力退化

如果被调用者没有实现接口,而我们还是希望利用动态代理机制,那么可以考虑其他方式。我们知道还有一种方式cglib,如果我们选择cglib方式,你会发现对接口的依赖 被克服了。cglib动态代理采取的是创建目标类的子类的方式,因为是子类化,我们 可以达到近似使用被调用者本身的效果。

JDK Proxy的优势:

  • 最小化依赖关系,减少依赖意味着简化开发和维护,JDK本身的支 持,可能比cglib更加可靠。
  • 平滑进行JDK版本升级,而字节码类库通常需要进行更新以保证在 新版Java上能够使用。
  • 代码实现简单。

基于类似cglib框架的优势:

  • 有的时候调用目标可能不便实现额外接口,从某种角度看,限定调 用者实现接口是有些侵入性的实践,类似cglib动态代理就没有这种 限制。
  • 只操作我们关心的类,而不必为其他相关类增加工作量。
  • 高性能。
0%