简述: 从这篇文章起,咱们将继续Kotlin邂逅设计模式系列篇中的第二篇代理模式。代理模式能够说不少初级中级开发者迷惑的设计模式。可是它确实应用很广,不用多说你们很是熟悉的Retrofit框架,内部使用了动态代理设计模式,以注解的方式简化网络请求参数传递,从而实现更高解耦。然而在Kotlin中有自然支持的属性代理语法特性,能够简化Java中代理模式实现的模板代理。java
代理模式(Proxy Pattern),又称委托模式,顾名思义就是一个对象的实现委托给另外一个代理对象来实现供外部调用。算法
为其余对象提供一种代理方式来控制对某个对象的访问,从而更好地保证了该对象对外使用的透明性。设计模式
当没法或不想直接访问某个对象或访问某个对象存在困难时能够经过一个代理对象来间接访问。代理能够实现方法加强,好比经常使用的日志,缓存等;也能够实现方法拦截,经过代理方法修改原方法的参数和返回值数组
代理模式在生活中很是常见,因为最近身边同事都在讨论买房,这里就以买房中介为例来介绍咱们今天的代理模式。首先咱们须要使用UML类图直观地表示出代理模式思想。缓存
由上面的UML的类图可知,主要涉及到四种角色:bash
在Java中实现静态代理仍是比较简单,只要按照上述UML中分析角色规则来定义就能轻松实现。这里就用Java先去实现上述例子:网络
//IPurchaseHouse: 抽象买房接口
interface IPurchaseHouse {
void inquiryPrice();//询价
void visitHouse();//看房
void payDeposit();//付定金
void signAgreement();//签合同
void payMoney();//付钱
void getHouse();//拿房
}
//HouseOwner: 房子拥有者(房东)
class HouseOwner implements IPurchaseHouse {//实现IPurchaseHouse共同接口
@Override
public void inquiryPrice() {
System.out.println("HouseOwner提出房子价格: 200W RMB");
}
@Override
public void visitHouse() {
System.out.println("HouseOwner赞成买房者来看房子");
}
@Override
public void payDeposit() {
System.out.println("HouseOwner收了买房者1W RMB定金");
}
@Override
public void signAgreement() {
System.out.println("HouseOwner与买房者签定合同");
}
@Override
public void payMoney() {
System.out.println("买房者付钱给HouseOwner");
}
@Override
public void getHouse() {
System.out.println("买房者拿到房子");
}
}
//HouseAgent: 房产中介
class HouseAgent implements IPurchaseHouse {
private IPurchaseHouse mHouseOwner;//具体房东HouseOwner被代理对象引用
public HouseAgent(IPurchaseHouse houseOwner) {
mHouseOwner = houseOwner;
}
@Override
public void inquiryPrice() {
mHouseOwner.inquiryPrice();//经过具体房东HouseOwner引用去调用inquiryPrice
}
@Override
public void visitHouse() {
mHouseOwner.visitHouse();//经过具体房东HouseOwner引用去调用visitHouse
}
@Override
public void payDeposit() {
mHouseOwner.payDeposit();//经过具体房东HouseOwner引用去调用payDeposit
}
@Override
public void signAgreement() {
mHouseOwner.signAgreement();//经过具体房东HouseOwner引用去调用signAgreement
}
@Override
public void payMoney() {
mHouseOwner.payMoney();//经过具体房东HouseOwner引用去调用payMoney
}
@Override
public void getHouse() {
mHouseOwner.getHouse();//经过具体房东HouseOwner引用去调用getHouse
}
}
//Client客户类
class Client {
public static void main(String[] args) {
IPurchaseHouse houseOwner = new HouseOwner();
IPurchaseHouse houseAgent = new HouseAgent(houseOwner);//传入具体被代理类实例
houseAgent.inquiryPrice();//询问价格
houseAgent.visitHouse();//看房
houseAgent.payDeposit();//支付定金
houseAgent.signAgreement();//签合同
houseAgent.payMoney();//付钱
houseAgent.getHouse();//拿房
}
}
复制代码
运行结果:数据结构
HouseOwner提出房子价格: 200W RMB
HouseOwner赞成买房者来看房子
HouseOwner收了买房者1W RMB定金
HouseOwner与买房者签定合同
买房者付钱给HouseOwner
买房者拿到房子
Process finished with exit code 0
复制代码
这就是静态代理具体的实现,可能有些并不能看到代理模式所带来的好处,看上去就像是代理类作了实际转发调用而已。实际上有个很明显优势就是: 能够在HouseAgent类中整个流程插入一些特有的操做或行为,而不会影响内部HouseOwner的实现,保护内部的实现。 还有一个优势就是代理类在保证HouseOwner核心功能同时能够扩展其余行为。app
上述结论可能有点抽象,假如如今有个不同需求好比A房产中介,在看房以前首先得签定一个看房协议,可是这个协议只涉及购买用户与中介之间的协议。因此基于代理模式很轻松就实现。框架
//修改后的HouseAgentA
class HouseAgentA implements IPurchaseHouse {
private IPurchaseHouse mHouseOwner;//具体房东HouseOwner被代理对象引用
private boolean mIsSigned;
public HouseAgentA(IPurchaseHouse houseOwner) {
mHouseOwner = houseOwner;
}
@Override
public void inquiryPrice() {
mHouseOwner.inquiryPrice();//经过具体房东HouseOwner引用去调用inquiryPrice
}
@Override
public void visitHouse() {
if (mIsSigned) {
System.out.println("您已经签定了看房协议,能够看房了");
mHouseOwner.visitHouse();//经过具体房东HouseOwner引用去调用visitHouse
} else {
System.out.println("很抱歉,您还没签定了看房协议,暂时不能看房");
}
}
public void signVisitHouseAgreement(boolean isSigned) {
mIsSigned = isSigned;
}
@Override
public void payDeposit() {
mHouseOwner.payDeposit();//经过具体房东HouseOwner引用去调用payDeposit
}
@Override
public void signAgreement() {
mHouseOwner.signAgreement();//经过具体房东HouseOwner引用去调用signAgreement
}
@Override
public void payMoney() {
mHouseOwner.payMoney();//经过具体房东HouseOwner引用去调用payMoney
}
@Override
public void getHouse() {
mHouseOwner.getHouse();//经过具体房东HouseOwner引用去调用getHouse
}
}
//Client客户类
class Client {
public static void main(String[] args) {
IPurchaseHouse houseOwner = new HouseOwner();
IPurchaseHouse houseAgent = new HouseAgentA(houseOwner);//传入具体被代理类实例
houseAgent.inquiryPrice();//询问价格
((HouseAgentA) houseAgent).signVisitHouseAgreement(true);//签定看房合同
houseAgent.visitHouse();//看房
houseAgent.payDeposit();//支付定金
houseAgent.signAgreement();//签合同
houseAgent.payMoney();//付钱
houseAgent.getHouse();//拿房
}
}
复制代码
运行结果:
HouseOwner提出房子价格: 200W RMB
您已经签定了看房协议,能够看房了
HouseOwner赞成买房者来看房子
HouseOwner收了买房者1W RMB定金
HouseOwner与买房者签定合同
买房者付钱给HouseOwner
买房者拿到房子
Process finished with exit code 0
复制代码
看到了Java中的HouseAgent和HouseAgent中代理类中实现转发委托是否是有点无脑啊,有点机械,就像是在写Java中的setter和getter方法同样,太多的样板代码。这时候把它叫给Kotlin吧,它会让你的代理类看起来更加简洁和优雅,由于在Kotlin中实现代理模式有着自然优点,熟悉Kotlin的小伙伴们都知道,在Kotlin中有代理独有语法特性,经过它就能轻松实现代理模式。
//IPurchaseHouseKt: 抽象买房接口
interface IPurchaseHouseKt {
fun inquiryPrice() //询价
fun visitHouse() //看房
fun payDeposit() //付定金
fun signAgreement() //签合同
fun payMoney() //付钱
fun getHouse() //拿房
}
//HouseOwnerKt: 房子拥有者(房东)
class HouseOwnerKt : IPurchaseHouseKt {
override fun inquiryPrice() {
println("HouseOwner提出房子价格: 200W RMB")
}
override fun visitHouse() {
println("HouseOwner赞成买房者来看房子")
}
override fun payDeposit() {
println("HouseOwner收了买房者1W RMB定金")
}
override fun signAgreement() {
println("HouseOwner与买房者签定合同")
}
override fun payMoney() {
println("买房者付钱给HouseOwner")
}
override fun getHouse() {
println("买房者拿到房子")
}
}
//HouseAgentKt: 房产中介. 注意了,重点来了,Kotlin只须要简单一行就替代了Java代理类全部样板代码
class HouseAgentKt(houseOwnerKt: IPurchaseHouseKt) : IPurchaseHouseKt by houseOwnerKt//经过by关键字实现代理,省略大量的代理类中的样板代码,这一点须要get
//Client调用处
fun main(args: Array<String>) {
val houseOwnerKt = HouseOwnerKt()
HouseAgentKt(houseOwnerKt).run {
inquiryPrice()//询问价格
visitHouse()//看房
payDeposit()//支付定金
signAgreement()//签合同
payMoney()//付钱
getHouse()//拿房
}
}
复制代码
运行结果:
HouseOwner提出房子价格: 200W RMB
HouseOwner赞成买房者来看房子
HouseOwner收了买房者1W RMB定金
HouseOwner与买房者签定合同
买房者付钱给HouseOwner
买房者拿到房子
Process finished with exit code 0
复制代码
可能有的小伙伴就会问了,你使用by关键字一下把全部的方法都给代理了,但是须要像上面新加的需求同样,须要在某个方法调用时插入一段逻辑。这个也很是方便,只须要重写须要改变的那个方法便可。一块儿来瞅瞅:
//修改后的HouseAgentAKt
class HouseAgentAKt(houseOwnerAKt: IPurchaseHouseKt) : IPurchaseHouseKt by houseOwnerAKt {
private val mHouseOwnerAKt = houseOwnerAKt
var mIsSigned: Boolean = false
override fun visitHouse() {//只须要重写visitHouse便可
if (mIsSigned) {
println("您已经签定了看房协议,能够看房了")
mHouseOwnerAKt.visitHouse()
} else {
println("很抱歉,您还没签定了看房协议,暂时不能看房")
}
}
}
//Client调用处
fun main(args: Array<String>) {
val houseOwnerKt = HouseOwnerKt()
HouseAgentAKt(houseOwnerKt).run {
mIsSigned = true
inquiryPrice()
visitHouse()
payDeposit()
signAgreement()
payMoney()
getHouse()
}
}
复制代码
运行结果:
HouseOwner提出房子价格: 200W RMB
您已经签定了看房协议,能够看房了
HouseOwner赞成买房者来看房子
HouseOwner收了买房者1W RMB定金
HouseOwner与买房者签定合同
买房者付钱给HouseOwner
买房者拿到房子
Process finished with exit code 0
复制代码
可能就会有小伙伴问了,在Kotlin中一个by关键字底层到底作了什么,为何能减小代理类中样板代码。
实际上,在Kotlin中代理类HouseAgentKt
的超类型IPurchaseHouseKt
后面的by houseOwnerKt
表示houseOwnerKt
将会在HouseAgentKt
中内部存储,而且编译器将自动生成委托给houseOwnerKt
的全部IPurchaseHouseKt
接口方法。
咱们能够一块儿来看下反编译后的代码,验证咱们的结论:
public final class HouseAgentKt implements IPurchaseHouseKt {
// $FF: synthetic field
private final IPurchaseHouseKt $$delegate_0;//houseOwnerKt的内部存储$$delegate_0
public HouseAgentKt(@NotNull IPurchaseHouseKt houseOwnerKt) {
Intrinsics.checkParameterIsNotNull(houseOwnerKt, "houseOwnerKt");
super();
this.$$delegate_0 = houseOwnerKt;
}
public void getHouse() {
this.$$delegate_0.getHouse();//委托给$$delegate_0(也便是传入的houseOwnerKt)getHouse方法
}
public void inquiryPrice() {
this.$$delegate_0.inquiryPrice();//委托给$$delegate_0(也便是传入的houseOwnerKt)inquiryPrice方法
}
public void payDeposit() {
this.$$delegate_0.payDeposit();//委托给$$delegate_0(也便是传入的houseOwnerKt)payDeposit方法
}
public void payMoney() {
this.$$delegate_0.payMoney();//委托给$$delegate_0(也便是传入的houseOwnerKt)payMoney方法
}
public void signAgreement() {
this.$$delegate_0.signAgreement();//委托给$$delegate_0(也便是传入的houseOwnerKt)signAgreement方法
}
public void visitHouse() {
this.$$delegate_0.visitHouse();//委托给$$delegate_0(也便是传入的houseOwnerKt)visitHouse方法
}
}
复制代码
如今咱们需求又增长了,如今须要增长多个代理中介,可能有不少小伙伴就说再去按照规则增长几个代理类就能够了。尽管Kotlin能解决Java中须要编写不少样板代码的问题,可是始终仍是静态的。所谓静态就是代理者类是须要开发者本身手动编写,在代码运行前代理类的class编译文件就已经存在。甚至,可能不是编译前就能决定的代理类的个数,而是在运行时肯定增长代理中介的个数,面对这样场景,静态代理可能就无能为力,那么就引出下面的动态代理
在Java中给咱们提供了一个很是方便的动态代理接口InvocationHandler
,只要实现这个接口而后重写它的抽象方法invoke()
//DynamicProxy类
class DynamicProxy implements InvocationHandler {
private Object object;//被代理类的引用
DynamicProxy(Object object) {//传入被代理类的实例引用
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(object, args);
}
}
//Client类
class Client {
public static void main(String[] args) {
IPurchaseHouse houseOwner = new HouseOwner();
DynamicProxy dynamicProxy = new DynamicProxy(houseOwner);
//Proxy.newProxyInstance方法动态构造一个代理中介,须要传入被代理类的ClassLoader、共同接口集合和dynamicProxy实例对象
IPurchaseHouse agentA = (IPurchaseHouse) Proxy.newProxyInstance(houseOwner.getClass().getClassLoader(), new Class[]{IPurchaseHouse.class}, dynamicProxy);
agentA.inquiryPrice();
agentA.visitHouse();
agentA.payDeposit();
agentA.signAgreement();
agentA.payMoney();
agentA.getHouse();
}
}
复制代码
运行结果:
HouseOwner提出房子价格: 200W RMB
HouseOwner赞成买房者来看房子
HouseOwner收了买房者1W RMB定金
HouseOwner与买房者签定合同
买房者付钱给HouseOwner
买房者拿到房子
Process finished with exit code 0
复制代码
实际上Java中的动态代理实现已经很是精简了,因此在Kotlin在动态代理实现并无特别不同的,它和Java的实现没有不一样。因此这里就再也不重复实现,只是换了Kotlin语言实现没有什么不同的。
动态代理与静态代理不一样点在于,它能够动态生成任意个代理对象,无须要开发者手动编写代理类代码。动态代理机制在运行时动态生成代理类字节码byte数组,而后经过jvm内部将字节码byte数组反序列化对应代理的Class对象,而后再经过反射机制建立代理类的实例。
Proxy.newProxyInstance
方法进入探究,经过它在外部更为直观是能够获取代理类对象。class Client {
public static void main(String[] args) {
IPurchaseHouse houseOwner = new HouseOwner();
DynamicProxy dynamicProxy = new DynamicProxy(houseOwner);
//第一步: 从Proxy.newProxyInstance方法入手
IPurchaseHouse agentA = (IPurchaseHouse) Proxy.newProxyInstance(
houseOwner.getClass().getClassLoader(),
new Class[]{IPurchaseHouse.class},
dynamicProxy
);
agentA.inquiryPrice();
agentA.visitHouse();
agentA.payDeposit();
agentA.signAgreement();
agentA.payMoney();
agentA.getHouse();
}
}
复制代码
Proxy.newProxyInstance
方法的定义Proxy.newProxyInstance
有三个参数:
loader(ClassLoader): 这个参数是实际被代理类的类加载器实例。
interfaces(Class<?>[]): 代理类和被代理类共同实现的接口的Class数组
h(InvocationHandler): 代理拦截器接口,通常须要使用子类去实现该接口或匿名类去实现
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();//将interfaces的Class数组clone一份副本,赋值给intfs
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {//检查建立一个新的代理类须要权限
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/* * Look up or generate the designated proxy class. */
//注意点1: getProxyClass0方法拿到代理类的Class对象实例cl
//注意传入的参数就是从外部传入的loader(被代理类的类加载器)、intfs(被代理类实现所接口的Class[]的副本)
Class<?> cl = getProxyClass0(loader, intfs);
/* * Invoke its constructor with the designated invocation handler. */
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//注意点2: 拿到cl实例后,就经过反射机制建立代理类实例
final Constructor<?> cons = cl.getConstructor(constructorParams);//先拿到代理类的构造器Constructor实例cons
final InvocationHandler ih = h;
//检查代理类构造器是不是公有的public权限, 不是就会经过AccessController去修改访问权限以至于能够建立代理类实例
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);//将访问权限设置为可访问的
return null;
}
});
}
//注意点3: 拿到构造器实例cons后,就到了最为关键的也就是最后一步,建立代理类实例。
//可是须要注意的是构造器反射传入的参数是h,也就是传入的InvocationHandler的实例,也能够进一步推论生成的代理类中存在以InvocationHandler为参数的构造器。
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);
}
}
复制代码
再一次来梳理下newProxyInstance
源码流程:
首先传入loader
、interfaces
、h
三个参数,先将interfaces
clone一份副本保存在intfs
中,而后检查建立一个新的代理类所须要的权限,接着到了咱们第一个注意点1,就是经过getProxyClass0
方法(须要传入loader
和intfs
参数)得到代理类的Class对象实例。拿到了代理类实例后,咱们就经过反射的机制建立代理类实例;
到了咱们的注意点二,经过代理类Class对象cl
得到构造器对象cons
,并检查构造器对象是不是public
,不然就强行修改访问权限;
最后到了注意点三,经过cons.newInstance
建立代理类对象,而且构造器反射中传入h(InvocationHandler对象)
,说明咱们能够推断一下生成的代理类中存在以InvocationHandler
为参数的构造器。
getProxyClass0
方法,传入的参数loader
和intfs
,在该方法内部会委托给proxyClassCache
的get方法,若是给定的类加载器中定义的代理类实现了给定的接口,直接返回缓存中的副本,不然它将经过ProxyClassFactory
建立代理类.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
//请注意上面那段英文注释: 若是给定的类加载器中定义的代理类实现了给定的接口,
//那么就会直接返回缓存中的副本,不然它将经过ProxyClassFactory建立代理类
//注意点1: proxyClassCache;注意点2: ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
复制代码
proxyClassCache
的介绍和定义, 请注意建立proxyClassCache
传入的构造器两个参数分别是: KeyFactory
和ProxyClassFactory
/** * a cache of proxy classes */
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
复制代码
proxyClassCache
是一个WeakCache<K,P,V>
对象,WeakCache<K,P,V>
中的K
表示key值,P
表明参数,V
表明存储的值。此类用于缓存(key, sub-key) -> value
键值对。内部具体实现是借助了ConcurentMap<Object, ConcurrentMap<Object, Supplier<V>>>
,Supplier
是一个接口,就一个get
方法用于得到值,不过是泛型V
的包装类,第一个Object
就是key(这里表达式不用泛型K
是由于key值能够为null),第二个就是sub-key
,那么它对应着什么呢? 并且具体的缓存中也没有泛型P
呢,这就须要引出另一个函数接口BiFunction<T, U, R>
,该接口内部存在R apply(T t, U u)
方法,这个方法意思就是根据传入两个泛型T
和U
的值通过必定计算获得泛型R
的值。在WeakCache<K,P,V>
类中存在两个BiFunction对象:
final class WeakCache<K, P, V> {
private final ReferenceQueue<K> refQueue
= new ReferenceQueue<>();
// the key type is Object for supporting null key
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
= new ConcurrentHashMap<>();
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
= new ConcurrentHashMap<>();
private final BiFunction<K, P, ?> subKeyFactory;
private final BiFunction<K, P, V> valueFactory;
public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) {
//根据K,P获得sub-key算法
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
//根据K,P获得value算法
this.valueFactory = Objects.requireNonNull(valueFactory);
}
...
}
复制代码
在WeakCahe
类中只有一个核心get
方法,里面包含了整个缓存的逻辑,注意咱们获取代理类Class对象,就是经过proxyClassCache.get(loader, interfaces);
实际上就是调用WeakCache
中的get
方法.
//K泛型是一级map的缓存key, P泛型传入的参数,分别对应外部传入的 loader和 interfaces
public V get(K key, P parameter) {
...
//经过传入一级map的key,经过CacheKey拿到最终
Object cacheKey = CacheKey.valueOf(key, refQueue);
// 懒初始化cacheKey对应的二级valuesMap, 若是valuesMap为空,就会新建立一个空的ConcurrentMap的valueMap,put到一级缓存map中
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
//若是valuesMap为空,就会新建立一个空的ConcurrentMap的valueMap
ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());
//若是内部已经存在原来的oldValuesMap直接用它
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
//------注意点1: subKeyFactory.apply(key, parameter)-----
//根据传入的一级map的key和参数parameter,经过subKeyFactory中的apply方法得到sub-key,
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
//而后经过咱们的sub-key,从二级缓存的valuesMap中取的supplier对象
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
//supplier这个对象多是Factory或CacheValue<V>对象,
//那么也就是supplier.get()方法多是调用了Factory中的get方法或CacheValue<V>中的get方法
//--------注意点2: supplier.get()-----
V value = supplier.get();
//若是value不为空就返回value,结束整个get方法调用
if (value != null) {
return value;
}
}
//若是缓存中没有supplier对象
//或者supplier中get返回是null
//或者Factory对象没有在CacheValue中被成功建立
//factory为null,就会建立一个新的Factory实例
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
//supplier为null
if (supplier == null) {
//根据新建立的factory和subKey拿到supplier对象,若是valuesMap中存在subKey, factory键值对,就返回已经存在的值,没有直接返回null
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
//若是拿到supplier为null,supplier就变为了factory,这就是前面说supplier为一个factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
//经过valuesMap.get()拿到supplier
supplier = valuesMap.get(subKey);
}
}
}
}
复制代码
咱们来一块儿梳理下WeakCache
的逻辑: 首先proxyClassCache
就是一个WeakCache
实例对象,它有两个构造器参数subKeyFactory
和valueFactory
,建立proxyClassCache
实例对应传入的是proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory())
中的KeyFactory
和ProxyClassFactory
.
而后在WeakCache
内部存在二级ConcurrentHashMap
, 一级map的key
就是get方法传入的key, 经过这个key拿到cacheKey
,从而拿到对应的valuesMap二级map
。
而后又经过根据传入的一级map的key
和参数parameter
,subKeyFactory
中的apply
方法得到sub-key
,经过sub-key
拿到二级map中存储的Supplier
对象,它多是一个CacheValue
也有多是一个Factory
,
最终经过Factory
的get
方法拿到实际的值。
对于上述有两个核心注意点
注意点1----->获取subKey过程: 经过subKeyFactory.apply(key,parameter)
拿到sub-key
//weakCache调用处:
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
//KeyFactory的定义
private static final class KeyFactory
implements BiFunction<ClassLoader, Class<?>[], Object>
{
@Override
public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
//能够看到是根据被代理类实现的接口的Class数组长度来决定选用哪种subKey
switch (interfaces.length) {
//对于被代理类只实现了1个接口状况,也是最频繁一种
case 1: return new Key1(interfaces[0]); // the most frequent
//对于被代理类只实现了2个接口状况
case 2: return new Key2(interfaces[0], interfaces[1]);
//对于被代理类只实现了0个接口状况
case 0: return key0;
//对于被代理类只实现了超过2个接口状况
default: return new KeyX(interfaces);
}
}
}
复制代码
注意点2----> supplier.get()获取value的过程:
咱们都知道supplier
对应的能够是Factory
对象,也就是最后会调用Factory中的get
方法。
@Override
public synchronized V get() { // serialize access
// 再一次检查supplier,若是传入从valuesMap拿到的不等于当前Factory对象,由于它可能已经变成CacheValue了,那就直接返回null
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
return null;
}
//建立一个新的value
V value = null;
try {
//注意点出现,value最终会经过valueFactory.apply(key, parameter)拿到
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// 判断value是否为null
assert value != null;
// 将拿到的value包装成一个CacheValue
CacheValue<V> cacheValue = new CacheValue<>(value);
// 尝试把valuesMap中的对应subKey的Factory替换成cacheValue,
//这就是为何前面说过valuesMap中取出的Supplier多是Factory多是CacheValue,有没有种偷梁换柱的赶脚
if (valuesMap.replace(subKey, this, cacheValue)) {
//替换成功后,并把cacheValue put到reverseMap中
reverseMap.put(cacheValue, Boolean.TRUE);
} else {
throw new AssertionError("Should not reach here");
}
// 成功替换了新的CacheValue,并返回最终的值
return value;
}
复制代码
经过上述代码分析,咱们知道最终value获取是来自于valueFactory
中apply
方法,还记得valueFactory
是啥吗?没错它就是ProxyClassFactory
也就是最终定位到了ProxyClassFactory
中的apply
方法。这也就是为何以前说若是缓存中有直接从缓存中返回缓存的副本,没有就在ProxyClassFactory中建立代理对象。
ProxyClassFactory
中的apply
方法进行探究,这是建立新的代理类Class对象惟一来源。private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 全部生成的代理类名称统一前缀$Proxy
private static final String proxyClassNamePrefix = "$Proxy";
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
//验证类加载器是否将此接口的名称解析为同一个Class对象
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");
}
//验证interfaceClass的Class对象是不是一个接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
//验证此接口不是重复的
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;
//记录非公共代理接口的包,以便proxy类将在同一个包中定义。验证全部非公共代理接口是否在同一个包中
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
//生成惟一的代理类名称标识
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//生成肯定的代理类Class文件的byte数组
//------注意点ProxyGenerator.generateProxyClass-----
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//经过defineClass0方法传入被代理类的类加载器、代理类惟一名称、生成的代理类文件反序列化成一个代理类的Class对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
复制代码
再从新梳理一下ProxyClassFactory
中的apply
中的逻辑,首先作一些接口验证操做,而后经过ProxyGenerator.generateProxyClass
生成肯定的代理类Class文件的byte数组,最后经过defineClass0方法传入被代理类的类加载器、代理类惟一名称、生成的代理类文件反序列化成一个代理类的Class对象
ProxyGenerator
中的generateProxyClass
方法进行探究,主要经过它来生成代理类Class文件。generateProxyClass
方法传入的参数主要有: proxyName(惟一代理类名称), interfaces(须要代理的接口Class数组), accessFlags(访问权限标识)public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
//-----注意点----调用ProxyGenerator中的generateClassFile方法
final byte[] var4 = var3.generateClassFile();
//是否须要把生成Class文件保存在本地文件中,这个标识能够从外部进行配置
//boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}
复制代码
generateClassFile()
方法,该方法主要生成Class文件。private byte[] generateClassFile() {
//---注意点1----在生成的代理类中加入Object类几个默认方法好比常见的hashCode、equal、toString方法
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
//取出代理类的接口的Class数组
Class[] var1 = this.interfaces;
int var2 = var1.length;
int var3;
Class var4;
//----注意点2---遍历代理类的接口的Class数组,将代理类接口中的方法加入生成的代理类中
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
//得到每一个接口中定义的全部方法Method对象
Method[] var5 = var4.getMethods();
int var6 = var5.length;
//而后再遍历全部的Method对象,并把它加入到生成的代理类中
for(int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
this.addProxyMethod(var8, var4);
}
}
...
try {
//----注意点3 生成的代理类中加入生成构造器方法generateConstructor----
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator();
...
//----注意点4 生成的代理类中加入生成静态初始化块----
this.methods.add(this.generateStaticInitializer());
} catch (IOException var10) {
throw new InternalError("unexpected I/O Exception", var10);
}
...
//建立字节数组输出流
ByteArrayOutputStream var13 = new ByteArrayOutputStream();
DataOutputStream var14 = new DataOutputStream(var13);
try {
...
var14.writeShort(this.fields.size());
var15 = this.fields.iterator();
//往输出流写入生成代理类Filed字段相关信息
while(var15.hasNext()) {
ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
var20.write(var14);
}
var14.writeShort(this.methods.size());
var15 = this.methods.iterator();
//往输出流写入生成代理类Method方法相关信息
while(var15.hasNext()) {
ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
var21.write(var14);
}
var14.writeShort(0);
//返回最终的Class文件的字节数组
return var13.toByteArray();
} catch (IOException var9) {
throw new InternalError("unexpected I/O Exception", var9);
}
}
}
复制代码
public final class $Proxy1 extends Proxy implements IPurchaseHouse {
private static Method m1;
private static Method m7;
private static Method m8;
private static Method m2;
private static Method m4;
private static Method m3;
private static Method m6;
private static Method m0;
private static Method m5;
//----注意点1 生成代理类中的构造器中有个InvocationHandler参数----
public $Proxy1(InvocationHandler var1) throws {
super(var1);//并把它传给它的父类Proxy中的h(InvocationHandler)
}
//生成equals方法
public final boolean equals(Object var1) throws {
try {
//---注意点出现super.h.invoke---
//委托父类`Proxy`中的`h`中的`invoke`方法来实现调用,并把当前生成的代理类实例this、当前方法对应的`Method`对象和参数数组`args`经过`invoke`回调出去,此时`InvocationHandler`子类中的`invoke`方法就会得以触发
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
//生成Object类中默认的hashCode方法
public final int hashCode() throws {
try {
//---注意点出现super.h.invoke---
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//生成Object类中默认的toString方法
public final String toString() throws {
try {
//---注意点出现super.h.invoke---
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//生成代理接口中的payDeposit方法
public final void payDeposit() throws {
try {
//---注意点出现super.h.invoke 同理---
super.h.invoke(this, m7, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//生成代理接口中的signAgreement方法
public final void signAgreement() throws {
try {
//---注意点出现super.h.invoke 同理---
super.h.invoke(this, m8, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//生成代理接口中的payMoney方法
public final void payMoney() throws {
try {
//---注意点出现super.h.invoke 同理---
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//生成代理接口中的getHouse方法
public final void getHouse() throws {
try {
//---注意点出现super.h.invoke 同理---
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//生成代理接口中的visitHouse方法
public final void visitHouse() throws {
try {
//---注意点出现super.h.invoke 同理---
super.h.invoke(this, m6, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//生成代理接口中的inquiryPrice方法
public final void inquiryPrice() throws {
try {
//---注意点出现super.h.invoke 同理---
super.h.invoke(this, m5, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//生成的静态初始化块中,经过反射拿到对应的方法Method对象,
//其中包括了Object中的方法和代理接口中的方法
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m7 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("payDeposit");
m8 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("signAgreement");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("payMoney");
m3 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("getHouse");
m6 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("visitHouse");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m5 = Class.forName("com.mikyou.design_pattern.delegates.dynamic.IPurchaseHouse").getMethod("inquiryPrice");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
复制代码
其实当你看到了生成的代理类的代码后,你就会发现动态代理的机制就很是一目了然。你也就明白了InvocationHandler
中的invoke
方法何时调用了。那咱们再来总体梳理下动态代理核心机制,其实最为核心的就是InvocationHandler
:
首先,咱们须要去实现一个InvocationHandler
的子类,重写它的invoke
方法,该方法中会回调三个参数: Object proxy, Method method, Object[] args
,而后在咱们在invoke
方法中只须要经过调用method
的invoke
方法,并传入args
参数。
而后咱们去建立一个代理类实例是经过Proxy.newProxyInstance
,会传入InvocationHandler
子类实例,并把这个InvocationHandler
子类实例做为生成新的代理类的构造器函数参数,并把这个参数传给新的代理类的父类Proxy
,在Proxy
中会维护这个InvocationHandler
子类实例h
。
而后经过上述生成的代理类代码来看,会把全部方法都转成对应的Method
对象,并在静态初始化块中经过反射进行初始化,而后每一个方法内部调用实现,都会委托父类Proxy
中的h
中的invoke
方法来实现调用,并把当前生成的代理类实例、当前方法对应的Method
对象和参数数组args
经过invoke
回调出去,此时InvocationHandler
子类中的invoke
方法会得以触发,那么在其内部又转为method
调用它的invoke
方法,并传入args
参数就至关于利用反射去调用这个方法。
最后到这里,有关动态代理内容就算说完了。
欢迎关注Kotlin开发者联盟,这里有最新Kotlin技术文章,每周会不按期翻译一篇Kotlin国外技术文章。若是你也喜欢Kotlin,欢迎加入咱们~~~
Kotlin邂逅设计模式系列:
数据结构与算法系列:
翻译系列:
原创系列:
Effective Kotlin翻译系列
实战系列: