静态代理
首先, 我们这里有一个接口Subject以及实现了Subject的RealSubject, 代码如下:
1
2
3
4public interface Subject {
void request();
}1
2
3
4
5
6
7public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject request");
}
}正常情况下, 我们调用RealSubject#request方式如下:
1
2RealSubject realSubject = new RealSubject();
realSubject.request();现在有一个需求: 我们想在不修改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
21public 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
30public 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
4RealSubject 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
分析
- 动态代理的关键在InvocationHandler#invoke方法
- 动态代理中使用了反射