盒子
盒子
文章目录
  1. 静态代理
  2. 动态代理
  3. 静态代理和动态代理的比较
  4. 动态代理源码简析
  5. 参考文章

Java 动态代理及源码简析

Android 中的 Retrofit 框架以及 Spring AOP 的内部实现都是基于 Java 动态代理机制来实现的,所以理解 Java 动态代理机制有助于我们阅读框架源码以及理解其实现思路。

Java 有两种代理方式,一种是静态代理,另外一种就是本文所介绍的动态代理

静态代理

静态代理比较简单,静态代理代理的是一个类,代理类和委托类(被代理类)都实现相同的接口,然后代理类内部持有委托类的引用,客户端只需要与代理类打交道,客户端调用代理类的方法时,代理类内部再调用委托类的方法,但在调用委托类方法的前后,代理类可以插入自己的代码,执行自己的逻辑,下面是一个静态代理的简单代码演示。

1
2
3
4
5
public interface IAnimal {

void say(String word);

}
1
2
3
4
5
6
7
8
public class Cat implements IAnimal {

@Override
public void say(String word) {
System.out.println("Cat: say()-->" + word);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class StaticAnimalProxy implements IAnimal{

private IAnimal animal;

public StaticAnimalProxy(IAnimal animal) {
this.animal = animal;
}

@Override
public void say(String word) {
System.out.println("静态代理前置代码");
animal.say(word);
System.out.println("静态代理后置代码");
}

}
1
2
StaticAnimalProxy proxy = new StaticAnimalProxy(new Cat());
proxy.say("hello!");
1
2
3
4
5
输出:

静态代理前置代码
Cat: say()-->hello!
静态代理后置代码

动态代理

上面说到静态代理代理的是一个类,动态代理代理的是一个接口,要想实现动态代理,必须要实现 InvocationHandler 这个接口,这个实现类可以理解为是一个调用处理器 (Handler),通过这个 InvocationHandler 的实现类和 Proxy 类的 newProxyInstance() 方法可以动态生成任何接口的代理类,下面是一个实现动态代理的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class DynamicProxyHandler implements InvocationHandler {

// 被代理的对象
private Object target;

public DynamicProxyHandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
System.out.println("动态代理前置代码");
// 这里真正调用被代理对象的方法,返回结果是方法的返回值,在这行代码前后可以实现额外的逻辑,实现代理功能。
Object result = method.invoke(target, args);
System.out.println("动态代理后置代码");
return result;
}

}
1
2
3
4
5
6
7
8
9
// 被代理的对象 cat
Cat cat = new Cat();
// 创建调用处理器,将 cat 作为参数传递进去,让处理器持有被代理对象 cat 的引用
DynamicProxyHandler proxyHandler = new DynamicProxyHandler(cat);
// 因为 Cat 实现了 IAnimal 接口,所以这里生成动态生成一个 IAnimal 的代理类
IAnimal animal = (IAnimal) Proxy.newProxyInstance(IAnimal.class.getClassLoader(), new Class[]{IAnimal.class}, proxyHandler);
animal.say("hello!");
// 返回的 animal 实际上不是真正的 animal,而是 animal 的代理类 com.sun.proxy.$Proxy0
System.out.println(animal.getClass().getCanonicalName());
1
2
3
4
动态代理前置代码
Cat: say()-->hello!
动态代理后置代码
com.sun.proxy.$Proxy0

静态代理和动态代理的比较

  • 静态代理代理的是一个类,动态代理的是接口。

  • 静态代理类在程序运行之前代理类 (.class) 就存在了,而动态代理是在程序运行时通过反射机制动态生成代理类。

    StaticAnimalProxy 只能代理 IAnimal 的实现类。

    DynamicProxyHandler 内部代理的是一个 Object,Proxy.newProxyInstance 方法可以为任一接口代理生成代理类,上面的例子代理的是 IAnimal 的代理类,当然也可以代理其他接口。

  • 相较于静态代理,动态代理的优点是实现无侵入式的代码扩展,可以在不修改源码的情况下去增强一些方法,在方法的前后做自己想做的事情,此外也还可以减少代码量,若使用静态代理,如果类的方法比较多的时候,需要手写大量的代码,而动态代理只需要在 InvocationHandlerinvoke() 方法中处理即可。

  • Java 的动态代理只能代理接口,若要动态代理类需要使用 CGLIB 库。

动态代理源码简析

从上面可以看到动态代理类是由 Proxy.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
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
Objects.requireNonNull(h);

...

/*
* Look up or generate the designated proxy class.
* 生成代理类 Class 对象
*/
Class<?> cl = getProxyClass0(loader, intfs);

/*
* Invoke its constructor with the designated invocation handler.
* 反射获取构造器生成代理类实例对象返回给调用者
*/
try {
...
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
...
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);
}
}

再主要看 getProxyClass0() 方法是如何生成代理类 Class 对象的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}

// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}

proxyClassCache 缓存了代理类对象,方便复用,proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); proxyClassCache 是一个 WeakCache 对象,其构造器的 ProxyClassFactory 对象很重要,看名字就知道了,这个类就是专门来生成代理类的,上面的 proxyClassCache.get() 方法最终也是调用了其 apply() 方法来生成并返回的代理类,所以下面来看 ProxyClassFactoryapply() 方法的内部实现。

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
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

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.
* 验证 Proxy.newProxyInstance() 传寄来的 classLoader 和 interfaces 是否有效
*/
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");
}
...
}

...

/*
* Choose a name for the proxy class to generate.
* 为代理类生成一个名字,这里 proxyClassNamePrefix 值为 "$Proxy" num 从 0 开始,
* 所以这里解释了为什么生成出来的代理类名字时 $Proxy0
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;

/*
* Generate the specified proxy class.
* 最终生成代理类 class 二级制文件,并存储来了本地,也就是运行时动态生成出了 .class 文件
*/
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());
}
}

当然我们也可以自己手动调用 ProxyGenerator.generateProxyClass() 方法来生成 .class 文件,然后反编译查看里面的内容,内部其实生成了接口的各个方法,然后再各个方法内部调用了 h (InvocationHandler)invoke(Object proxy, Method method, Object[] args) 方法,转到了调用层。

  • proxy : 代理类
  • method : 调用的方法信息
  • args : 调用该方法的参数

以上就是 Java 动态代理的介绍与分析,Spring 的 AOP 以及 Android Retrofit 框架的接口注解实现就是基于动态代理实现的,好像是基于 CGLIB,不过原理大多都是想通的。

参考文章

赞赏
扫一扫,支持 Melody
  • 微信二维码
  • 支付宝二维码