动态代理基本原理

  • 代理
    为对象提供一个代理类,通过代理类调用对象的方法

  • 动态代理
    运行时生成代理。

动态代理的实现

自定义一个业务接口

1
2
3
public interface IRepository {
void request();
}

实现InvocationHandler接口,并可以在method方法封装自己的业务逻辑。

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

private IRepository repository;

public RepositoryInvocationHandler(IRepository repository) {
this.repository = repository;
}

@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
// ... 在调用方法前加入实现
method.invoke(repository, args); // 这一步是真正调用了业务接口
// ... 在调用方法后加入实现
return null;
}

}
1
2
3
4
5
6
7
8
// 生成RepositoryInvocationHandler实例
RepositoryInvocationHandler repositoryInvocationHandler = new RepositoryInvocationHandler(repository);

// 生成代理类传入IRepository业务接口和RepositoryInvocationHandler实例
proxy = (IRepository) (Proxy.newProxyInstance(IRepository.class.getClassLoader(), new Class[]{IRepository.class}, repositoryInvocationHandler));

// 于是可以调用代理类的方法,执行具体的业务接口
proxy.request();

动态代理的原理

顺着流程看看动态代理的生成逻辑。

动态代理通过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
public static Object newProxyInstance(ClassLoader loader,   // 接口类的ClassLoade
Class<?>[] interfaces, // 接口
InvocationHandler h) // 实现的Handlerthrows IllegalArgumentException
{
...

// 克隆业务接口
final Class<?>[] intfs = interfaces.clone();

// 查询或生成代理类
Class<?> cl = getProxyClass0(loader, intfs);

// 获取代理类构造函数
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});

...
}

查询或生成代理类。

1
2
3
4
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
// 通过WeakCache缓存获取,如果缓存没有则通过ProxyClassFactory生成
return proxyClassCache.get(loader, interfaces);
}

WeakCache里面持有一个ProxyClassFactory引用,通过proxyClassCache.get方法获取代理类,调用了ProxyClassFactory.apply方法。

具体看看ProxyClassFactory.apply方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

// 递归获取业务方法列表
List<Method> methods = getMethods(interfaces);
Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
validateReturnTypes(methods);

// 获取异常列表
List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);

Method[] methodsArray = methods.toArray(new Method[methods.size()]);
Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);

long num = nextUniqueNumber.getAndIncrement();
// 生成proxyName,例如"$proxy0"
String proxyName = proxyPkg + proxyClassNamePrefix + num;

// 通过native方法返回一个代理类
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);

先解析业务接口的方法,然后通过native方式生成代理类。

看一下具体的$Proxy0代理类:(代理类生成在内存)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public final class $Proxy0 extends Proxy implements IRepository {

public $Proxy0(InvocationHandler var1) throws {
super(var1);
}

public final void request() throws {
try {
// 调用InvocationHandler的invoke方法
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

}

整个流程如下:

  1. 业务接口IRepository和实现业务代理操作类RepositoryInvocationHandler传入Proxy的newProxyInstance;
  2. 通过Proxy生成具体动态代理类$Proxy0;
  3. 执行proxy.request()时,其实调用的是$Proxy0的request方法,最终调用的是RepositoryInvocationHandler;
  4. RepositoryInvocationHandler里是我们自己的实现,method.invoke(repository, args)反射调用了IRepository具体业务逻辑。

Done.

参考文章:
Java动态代理实现及原理分析

0%