静态代理

  1. 首先, 我们这里有一个接口Subject以及实现了Subject的RealSubject, 代码如下:

    1
    2
    3
    4
    public interface Subject {

    void request();
    }
    1
    2
    3
    4
    5
    6
    7
    public class RealSubject implements Subject {

    @Override
    public void request() {
    System.out.println("RealSubject request");
    }
    }
  2. 正常情况下, 我们调用RealSubject#request方式如下:

    1
    2
    RealSubject realSubject = new RealSubject();  
    realSubject.request();
  3. 现在有一个需求: 我们想在不修改RealSubject代码的前提下, 获取RealSubject#request的执行时间(RealSubject#request方法的增强).
    可以使用静态代理模式, 优雅地实现这种需求.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class StaticSubject implements Subject{

    private RealSubject realSubject;

    public StaticSubject(@NotNull RealSubject realSubject) {
    this.realSubject = realSubject;
    }

    @Override
    public void request() {
    long startTime = System.currentTimeMillis();
    //可以在这里做代码增强
    System.out.println("before request");
    //当然, 不一定非要调用realSubject#request, 可以注释掉, 去实现一个完全新的方法
    realSubject.request();
    //可以在这里做代码增强
    System.out.println("after request");
    long endTime = System.currentTimeMillis();
    System.out.println("the time taken by request is "+(endTime - startTime));
    }
    }

动态代理

静态代理的问题以及优化

上面的静态代理有个问题, 接口Subject如果只有一两个方法, 那静态代理还很简单, 如果接口Subject中有很多(比如说十个), 那么, 使用静态代理的话, StaticSubject就需要实现Subject的全部方法(比如说十个之多), 那就很繁琐了. 这个时候, 我们就需要考虑, 有没有更优雅的实现方式呢? 这就引出了我们的主题: 动态代理. 使用动态代理的实现方式如下:

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
public class DynamicSubject implements InvocationHandler {

private Object sub;

public DynamicSubject(Object sub) {
this.sub = sub;
}

public Subject bind() {
Class<Subject> subjectClass = Subject.class;
return (Subject) Proxy.newProxyInstance(subjectClass.getClassLoader(),
new Class[]{subjectClass},
this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----->invoke, proxy: " + proxy.getClass().getName());
System.out.println("----->invoke, sub: " + sub);
//通过反射调用sub中的method方法
// Object invoke = method.invoke(sub, args);
// System.out.println("after calling " + method);
// return invoke;
long startTime = System.currentTimeMillis();
method.invoke(sub, args);
long endTime = System.currentTimeMillis();
System.out.println("the time taken by "+method.getName()+" is " + (endTime - startTime));
return null;
}
}

1
2
3
4
RealSubject realSubject = new RealSubject();
DynamicSubject dynamicSubject = new DynamicSubject(realSubject);
Subject subject = dynamicSubject.bind();
subject.request();

打印的日志如下
1
2
3
4
5
6
7
8
9
10
----->invoke, proxy: com.sun.proxy.$Proxy0
----->invoke, sub: proxy.RealSubject@4b67cf4d
before calling public abstract void proxy.Subject.request()
RealSubject request
the time taken by request is 2
----->invoke, proxy: com.sun.proxy.$Proxy0
----->invoke, sub: proxy.RealSubject@4b67cf4d
before calling public java.lang.String java.lang.Object.toString()
the time taken by toString is 0
subject: null

分析

  1. 动态代理的关键在InvocationHandler#invoke方法
  2. 动态代理中使用了反射

参考