之前和同学聊起代理模式,顺嘴提到了动态代理,就顺便看了一下源码,话不多说,开始分析,和之前一样为了方便理解,我会直接在代码中注释
这是一段很常见的动态代理代码,TestInterface是一个接口,里面只有一个test方法,TestInterfaceImpl类实现了TestInterface接口,代码也比较简单,我就不全部贴出来了
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test implements InvocationHandler {
public TestInterface ti;
public Object newProxyInstance(TestInterface ti) {
this.ti = ti;
//重点
return Proxy.newProxyInstance(ti.getClass().getClassLoader(), ti.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行方法前的操作");
if(method.getName().equals("test"))
{
ti.test();
}
System.out.println("执行方法后的操作");
return null;
}
public static void main(String[] args) {
Test test =new Test ();
TestInterface ti = (TestInterface)test.newProxyInstance(new TestInterfaceImpl());
ti.test();
}
}
重点是Proxy.newProxyInstance方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
//若传入的动态代理类为空抛出异常
Objects.requireNonNull(h);
//获取当前系统的安全检查器
//因为这里会进行类加载和io操作,需要进行安全检查
final Class<?> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();
/*
* Look up or generate the designated proxy class and its constructor.
*/
//关键方法
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
//此处只是调用Constructor的newInstance方法
//把动态代理对象传入,调用对应的构造方法
//返回一个动态代理后的实体类
//意义不大,这里就不多介绍
return newProxyInstance(caller, cons, h);
}
进入关键方法getProxyConstructor
private static Constructor<?> getProxyConstructor(Class<?> caller,
ClassLoader loader,
Class<?>... interfaces)
{
//判断需要代理的接口是否为多个,进行简单转换
//if else内容几乎一致,就只对前面的if内容进行分析,不再赘述
if (interfaces.length == 1) {
Class<?> intf = interfaces[0];
//判断是否需要进行安全检查
if (caller != null) {
checkProxyAccess(caller, loader, intf);
}
//重点方法,我会进行单独讲解
return proxyCache.sub(intf).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
} else {
// interfaces cloned
final Class<?>[] intfsArray = interfaces.clone();
if (caller != null) {
checkProxyAccess(caller, loader, intfsArray);
}
final List<Class<?>> intfs = Arrays.asList(intfsArray);
return proxyCache.sub(intfs).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
}
}
这段代码相当优雅,把lanbda表达式写的出神入化(但是我不建议大家平时这样写,可读性极差,我自己看这段代码蒙了有一会)
return proxyCache.sub(intf).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
首先我们来看computeIfAbsent方法
public V computeIfAbsent(ClassLoader cl,
BiFunction<
? super ClassLoader,
? super CLV,
? extends V
> mappingFunction)
lanbda表达式推导的就是BiFunction接口的方法,进入BiFunction接口
public interface BiFunction<T, U, R> {
R apply(T t, U u);
。。。省略。。。
}
问题来了,我们可以把lanbda表达式写成下面的代码
R apply(T ld, U clv){
return new ProxyBuilder(ld, clv.key()).build();
}
然后通过类型推导(根据computeIfAbsent方法进行推导)将代码推导为
R apply(ClassLoader ld, U clv){
return new ProxyBuilder(ld, clv.key()).build();
}
再根据sub方法,和AbstractClassLoaderValue,Sub类进行进一步的推导