设计模式8.5-动态代理

先有设计的思想,后才有设计的手段

代理

代理模式是java设计模式的一种。代理类具有和委托类相同的接口,代理类主要负责为委托类预处理消息、过滤消息、消息转发、以及事后处理消息等。

静态代理

由程序员创建或由特定工具自动生成源代码,在对其编译。在程序运行前,代理类的.class文件就已经存在

静态代理通常只代理一个类。同时静态代理需要明白代理的是什么

sample:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//定义代理接口
public interface ProxyInterface{
void doSomething();
}

public class A implements ProxyInterface{
@Override
void doSomething(){
...
}
}

public class AProxy implements ProxyInterface{
private ProxyInterface a;
public AProxy(ProxyInterface a){
this.a = a;
}

@Override
void doSomething(){
a.doSomething();
}
}

优点

静态代理从我们日常开发的角度来看,就是一个封装类,比较简单

缺点

局限性很大,尤其是限于对代理类的了解。在接手一个项目,发生问题的时候或许可以使用这种代理方式来进行优化

动态代理

动态代理类的字节码由java反射机制动态生成,无需手动编写源代码。

sample:

1
2
3
4
5
6
//创建InvocationHandler
InvocationHandler handler = new MyInvocationHandler(...);
//创建动态代理类
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),new Class[]{Foo.class});
//创建动态代理类的实例
Foo foo = (Foo)proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(new Object[]{handler});

这样就获取了类了。

原理

newProxyInstance

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
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);

final Class<?>[] intfs = interfaces.clone();
// Android-changed: sm is always null
// final SecurityManager sm = System.getSecurityManager();
// if (sm != null) {
// checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
// }

/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);

/*
* Invoke its constructor with the designated invocation handler.
*/
try {
// Android-changed: sm is always null
// if (sm != null) {
// checkNewProxyPermission(Reflection.getCallerClass(), cl);
// }

final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
// Android-changed: Removed AccessController.doPrivileged
cons.setAccessible(true);
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}

细致的看这个方法的内容

第一步 检查handler是否是空,这个没得说的

第二步 通过传入进去的classloader和class的方法来生成一个新的代理类(这中间有缓存)(class层级)

第三步 调用代理的构造器,将handler传入,构造了一个相应的类。

getProxyClass0():就是用来生产代理类的类对象

1
2
3
4
5
6
7
8
9
10
11
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 当目标类实现的接口数量大于 65535
if (interfaces.length > 65535) {
// 抛异常
throw new IllegalArgumentException("interface limit exceeded");
}

// 关键2:获取代理类,使用了缓存机制
return proxyClassCache.get(loader, interfaces);
}

WeakCache#get()

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 缓存的底层实现,key 为一级缓存,value 为二级缓存,一级缓存 key 类型为 Object,支持 null
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
= new ConcurrentHashMap<>();

// key:classloader
// parameter:interfaces
public V get(K key, P parameter) {
// 判断接口数组是否为空,为空抛异常,不为空返回接口对应类型
Objects.requireNonNull(parameter);

// 清除过期的缓存
expungeStaleEntries();

// 将传入的 classloader 包装成 CacheKey,作为一级缓存
Object cacheKey = CacheKey.valueOf(key, refQueue);

// 根据一级缓存 cacheKey 获取二级缓存 valuesMap
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
// 如果根据 classLoader 没有获取到对应的值
if (valuesMap == null) {
// 以 CAS 方式放入,如果不存在则放入,否则返回原先的值
ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
// 如果 oldValuesMap 有值,说明放入失败
if (oldValuesMap != null) {
// valuesMap 设置为原来的 oldValuesMap
valuesMap = oldValuesMap;
}
}

// subKeyFactory 通过 WeakCache 构造函数传入,实际为 KeyFactory
// subKeyFactory.apply(key, parameter):KeyFactory 根据代理类实现的接口数组来生成二级缓存 key
// Objects.requireNonNull():判断得到的二级缓存 key 是否为空,为空抛异常,不为空返回二级缓存 key 对应类型 Object
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 根据二级缓存的 key 获取二级缓存的值 supplier
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;

while (true) {
// 如果二级缓存的值 supplier 不为 null
if (supplier != null) {
// 调用 get() 方法
// 关键4:Factory implements Supplier,则此处实际调用的是 Factory#get()
V value = supplier.get();
// value 不为空
if (value != null) {
// 返回 value
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)

// 如果 factory 等于 null
if (factory == null) {
// 实例化一个 Factory(作为二级缓存的值),作为 subKey (二级缓存的 key)对应的 value
factory = new Factory(key, parameter, subKey, valuesMap);
}

// 如果 supplier 等于 null(根据二级缓存的 key 没有获取到二级缓存的值 supplier)
if (supplier == null) {
// 将实例化的 factory 作为 subKey 对应的值传入
supplier = valuesMap.putIfAbsent(subKey, factory);
// supplier 等于 null(可能上一步成功执行后返回的是 null???)
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else { // 可能期间有其他线程修改了值,那么就不会再继续给 subKey 赋值,而是取出来直接用
// 期间可能其它线程修改了值 factory,就用该值替换掉 supplier
if (valuesMap.replace(subKey, supplier, factory)) {
// 将 supplier 替换成 factory
supplier = factory;
} else {
// 替换失败,继续使用原先的值
supplier = valuesMap.get(subKey);
}
}
}
}

Factory#get()

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
public synchronized V get() { // serialize access
// 根据二级缓存的 key 获取 supplier
Supplier<V> supplier = valuesMap.get(subKey);
// 如果获取的 supplier 不是 Factory 类型
if (supplier != this) {
return null;
}
// else still us (supplier == this)

// create new value
V value = null;
try {
// valueFactory 通过 WeakCache 构造函数传入,实际为 ProxyClassFactory
// 关键5:valueFactory.apply()->ProxyClassFactory#apply()
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;

// wrap value with CacheValue (WeakReference)
CacheValue<V> cacheValue = new CacheValue<>(value);

// try replacing us with CacheValue (this should always succeed)
if (valuesMap.replace(subKey, this, cacheValue)) {
// put also in reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
} else {
throw new AssertionError("Should not reach here");
}

// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}

ProxyClassFactory#apply()

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Proxy 的类名前缀
private static final String proxyClassNamePrefix = "$Proxy";

// next number to use for generation of unique proxy class names
// 生成自增的数字
private static final AtomicLong nextUniqueNumber = new AtomicLong();

@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

// 根据接口数组长度生成对应的 Map
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
// 遍历接口数组
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*
* 验证类加载器将此 interface 的名字解析成同一类对象
*/
Class<?> interfaceClass = null;
try {
// 根据接口名获取接口对应的类对象
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
// 接口类对象不等于接口,不是同一对象
if (interfaceClass != intf) {
//抛异常,接口来自不同的类加载器
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*
* 验证生成的类对象是否是一个接口类型
*/
// 类对象不是接口类型
if (!interfaceClass.isInterface()) {
// 抛异常,类对象不是一个接口类型
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*
* 验证此接口不是重复的
*/
// 往接口数组对应的 map 中存入类对象,返回值不为 null
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
// 抛异常,来自当前类对象的接口重复
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}

String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
// 遍历接口数组
for (Class<?> intf : interfaces) {
// 获取当前接口的修饰符
int flags = intf.getModifiers();
// 如果当前接口修饰符不是 public
if (!Modifier.isPublic(flags)) {
// 设置为 final
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
// 包名为 null
if (proxyPkg == null) {
// 包名等于当前接口的包名
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {// 如果包名不相等
// 抛异常,非 public 的接口集合来自不同的包
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}

// 包名为 null
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
// 如果 no non-public(即是 public)的代理接口集合,则使用包名 com.sun.proxy
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}

/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
// 组成代理类全类名:包名 + 代理类前缀 + 唯一的自增长数字
String proxyName = proxyPkg + proxyClassNamePrefix + num;

/*
* Generate the specified proxy class.
*
* 关键6:生成指定的代理类
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}

生成代理类的字节码

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
最终生成的代理类:
public class Proxy0 extends Proxy implements IDinner {
// 第一步:生成构造器
protected Proxy0(InvocationHandler h) {
super(h);
}
// 第二步:生成静态域
private static Method m1; // hashCode方法
private static Method m2; // equals方法
private static Method m3; // toString方法
private static Method m4; //...
// 第三步:生成代理方法
@Override
public int hashCode() {
try {
return (int) h.invoke(this, m1, null);
}catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public boolean equals(Object obj) {
try {
Object[] args = new Object[] {obj};
return (boolean) h.invoke(this, m2, args);
}catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public String toString() {
try {
return (String) h.invoke(this, m3, null);
}catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public void dinner() {
try {
// 构造参数数组,如果有多个参数往后面添加就行了
Object[] args = new Object[] {};
// h 为通过构造方法传进来的 InvocationHandler,即此处调用 InvocationHandler#invoke(...) 方法
h.invoke(this, m4, args);
}catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
// 第四步:生成静态初始化方法
static {
try {
Class c1 = Class.forName(Object.class.getName());
Class c2 = Class.forName(IDinner.class.getName());
m1 = c1.getMethod("hashCode", null);
m2 = c1.getMethod("equals", new Class[]{Object.class});
m3 = c1.getMethod("toString", null);
m4 = c2.getMethod("dinner", new Class[]{IDinner.class});
//...
}catch (Exception e) {
e.printStackTrace();
}
}
}

InvocationHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* {@code InvocationHandler} is the interface implemented by
* the <i>invocation handler</i> of a proxy instance.
*
* <p>Each proxy instance has an associated invocation handler.
* When a method is invoked on a proxy instance, the method
* invocation is encoded and dispatched to the {@code invoke}
* method of its invocation handler.
*
* @author Peter Jones
* @see Proxy
* @since 1.3
*/

从其类注释上面可以看出来,每一个代理实例都有一个相关的调用handler,当一个代理实例的方法被唤醒的时候,该被代理的方法将会被编码并且分发到invocation handler中

具体来讲事实上是个回调接口类

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
/**
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
*
* @param proxy the proxy instance that the method was invoked on
*
* @param method the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance. The declaring
* class of the {@code Method} object will be the interface that
* the method was declared in, which may be a superinterface of the
* proxy interface that the proxy class inherits the method through.
*
* @param args an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* or {@code null} if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* {@code java.lang.Integer} or {@code java.lang.Boolean}.
*
* @return the value to return from the method invocation on the
* proxy instance. If the declared return type of the interface
* method is a primitive type, then the value returned by
* this method must be an instance of the corresponding primitive
* wrapper class; otherwise, it must be a type assignable to the
* declared return type. If the value returned by this method is
* {@code null} and the interface method's return type is
* primitive, then a {@code NullPointerException} will be
* thrown by the method invocation on the proxy instance. If the
* value returned by this method is otherwise not compatible with
* the interface method's declared return type as described above,
* a {@code ClassCastException} will be thrown by the method
* invocation on the proxy instance.
*
* @throws Throwable the exception to throw from the method
* invocation on the proxy instance. The exception's type must be
* assignable either to any of the exception types declared in the
* {@code throws} clause of the interface method or to the
* unchecked exception types {@code java.lang.RuntimeException}
* or {@code java.lang.Error}. If a checked exception is
* thrown by this method that is not assignable to any of the
* exception types declared in the {@code throws} clause of
* the interface method, then an
* {@link UndeclaredThrowableException} containing the
* exception that was thrown by this method will be thrown by the
* method invocation on the proxy instance.
*
* @see UndeclaredThrowableException
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;

参数的方法表现的就比较容易理解了。

proxy是指代理类的实例,method是指代理类的方法,每当代理类有方法经过时,这个method就会变成那个方法,args是方法的形式参数,这个地方也会截断。

返回值有几种情况

1、声明的返回类型是基础类型,返回值必须是对应的包装类实例

2、如果声明的返回类型是基础类型,但是返回了一个null的话,会报空指针异常

3、如果这个方法的返回值和声明的返回值不兼容的话,会报类型转换异常

总结

类A写死持有B,就是B的静态代理。如果A代理的对象是不确定的,就是动态代理。动态代理借用反射机制,最终生成的代理类和静态代理生成的相同

Q&A

动态代理模式和装饰者模式的区别

  • 装饰者模式的作用:在不使用继承、不改变原有对象的情况下增加或扩展对象行为,但是并不会禁用某个对象的行为

  • 代理模式:控制了这个对象的访问,决定执行或者不执行

动态代理模式有缺点吗?

由于是反射机制,创建一个动态代理类大约需要13ms,对比与反射一个方法只需要2ms来看,如果消耗过大还是需要考虑一下的