为什么要使用动态代理?

首先,我来看一下设计模式中常见的代理模式,也就是所谓的静态代理。

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
interface Subject {
public void doSomething();
}

class RealSubject implements Subject {
public void doSomething() {
System.out.println("call doSomething()");
}
}

class SubjectProxy implements Subject {
Subject subimpl = new RealSubject();

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

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

// 代理RealSubject的doSomething()方法
public void doSomething() {
// TODO:前置增强
before();

subimpl.doSomething();

// TODO:后置增强
after();
}
}

public class TestProxy {
public static void main(String args[]) {
Subject sub = new SubjectProxy();
sub.doSomething();
}
}

这种模式通过代理类对原来类的方法实现了封装和增强,即在原来的方法的前后嵌入代码片段。这种方法比较容易看懂,但是静态代理的这种写法有一个很大的问题,就是在一个类要增强的方法越来越多的时候,代理需要分别对每个方法进行增强,这样使代理类的代码量非常庞大。

因此,就引入了动态代理来解决这个问题。看一下代码:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Subject {
public void doSomething1();

public void doSomething2();
}

class RealSubject implements Subject {
public void doSomething1() {
System.out.println("call doSomething 1()");
}

public void doSomething2() {
System.out.println("call doSomething 2()");
}
}

class ProxyHandler implements InvocationHandler {
private Object tar;

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

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

// 绑定委托对象,并返回代理类
public Object bind(Object tar) {
this.tar = tar;
// 绑定该类实现的所有接口,取得代理类
return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 这里就可以进行所谓的AOP编程了

// TODO:前置增强
before();

result = method.invoke(tar, args);

// TODO:后置增强
after();

return result;
}
}

public class TestProxy {
public static void main(String args[]) {
ProxyHandler proxy = new ProxyHandler();
// 绑定该类实现的所有接口
Subject sub = (Subject) proxy.bind(new RealSubject());
sub.doSomething1();
sub.doSomething2();
}
}

打印结果:

1
2
3
4
5
6
before call
call doSomething 1()
after call
before call
call doSomething 2()
after call

看完这段代码,相信大家应该已经非常清楚Java动态代理的作用了。就是将Proxy类的代码量固定下来,不会因为被代理类的业务逐渐增大而增大

实际上,Spring的AOP和AspectJ就是基于动态代理技术实现的,而且它们能在配置文件中设置一些信息使代理更好用,更灵活。这也是Spring为什么这么受欢迎的原因之一,用SpringAOP代替JDK动态代理,让面向切面编程更容易实现。

现在Java的动态代理主要分为Java自己提供的JDK动态代理和CGLib(Code Generation Library)。JDK动态代理只能代理接口类,而CGLib这种则是直接修改字节码。

坚持原创技术分享,您的支持将鼓励我继续创作!
显示 Gitment 评论