先来理一下概念实践
代理三要素
形象主题角色(Subject)具体主题角色(RealSubject)
代理主题角色(Proxy)
代理关系图
栗子
Subject:购房需要RealSubject:小明的购房需要
Proxy: 中介A(只为小明服务)
中介能够帮忙或者代理小明做一些事件,比方筛选房源、预沟通等等,这就是代理的益处,业余、高效。
然而有以下问题:
1、中介A只为小明服务,如果小红、小强都要买房,怎么办呢?
2、小明还有买车需要,也想找中介帮忙,怎么办呢? 中介A懂房但不懂车。
问题
动态代理
中,此时就须要new 新的代理类,无论怎么形象、怎么封装,一个代理类总是能力无限的。 要为每个指标Subject
编写对应的代理类
,随着零碎宏大,工作量会剧增,并且可维护性变差。 那么思考,面对变动万千的subject
,如何能力少写代理类,或者不写代理类,又能实现代理性能呢?
思考方向: 一个接口(subject
) --》如何失去一个代理类proxy
? 这不是主动生成类吗? 是的,反射、Class
。
这就是动静代理。
《2020最新Java根底精讲视频教程和学习路线!》
Java的解决方案,动静代理
Java用jdk提供的Proxy
和InvocationHandler
联合实现动静代理性能。 先来看一段应用栗子
// 获取 买房需要 的ClassClass<?> proxyClass = Proxy.getProxyClass(BuyHouse.class.getClassLoader(), BuyHouse.class);// 通过Class的结构器Constructor 动态创建对立的代理服务LianjiaConstructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);BuyHouse lianjia = (BuyHouse) constructor.newInstance(new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 这里就能够随便增加服务了 // 依据不同人的需要,筛选房子 XiaomingBuyHouse xiaomingBuyHouse = new XiaomingBuyHouse(); System.out.println("Lianjia帮每个人筛选好房子"); // RealSubject,实在客户的看房行为 Object result = method.invoke(xiaomingBuyHouse, args); // 有了这个动静代理的性能,相当于能主动动静生成合乎每个人需要的独立的代理服务 // 这样单个中介 变成了 中介公司。效率更高、服务更好了 return result; }});lianjia.seekHouse();// 简写BuyHouse lianjia2 = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), new Class[]{ BuyHouse.class }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 进行代理 return null; }});lianjia2.seekHouse();复制代码
能够看到,java实现的动静代理离不开这几个外围点
1、Proxy.getProxyClass 或者 Proxy.newProxyInstance2、InvocationHandler#invoke
3、反射
动静代理里,反射是贯通始终的。
大家可能会奇怪, 一个 Proxy 一个InvocationHandler,底层到底做什么了,怎么就能代理了呢?咱们也没看到调用 InvocationHandler的要害办法 invoke啊。
源码剖析
上面简略看源码剖析一下。
getProxyClass0(loader, intfs)
咱们重点关注参数里的interfaces
和invocationHandle
,无论是 Proxy.newProxyInstance()
形式 还是 getProxyClass()
形式,重点都落在了getProxyClass0(loader, intfs)
是的,这就是代理类的外围生成逻辑。
proxyClassCache.get(loader, interfaces)
对代理类的缓存策略,后边就能看进去,这是十分有必要的,这个缓存数据构造相当简单,咱们找到外围的点:
咱们看到proxyClassCache.get(loader, interfaces)
,无论如何缓存,找return
就对了。
if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance V value = supplier.get(); if (value != null) { return value; }}复制代码
supplier.get()
而后就是 supplier.get()
,也就是 java.lang.reflect.WeakCache.Factory#get
而这里的重点是 value = Objects.requireNonNull(valueFactory.apply(key, parameter));
注:Objects.requireNonNull()返回值 还是参数自身哈,仅仅是进行非空判断,
public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }复制代码
所以这里的重点就是 valueFactory.apply(key, parameter);
而valueFactory
是什么呢?
是的,终于扯到要害了 ProxyClassFactory
。
java.lang.reflect.Proxy.ProxyClassFactory#apply
到这里根本理顺了,所以动静代理的外围,还是利用下面讲到的反射等技术,动静生成代理类的过程。
ProxyClassFactory#apply
办法里省略里很多逻辑,大家能够开展一下,必定会似曾相识。
比方:
- 在代码中能够看到JDK生成的代理类的类名是“$Proxy”+序号。
- 如果接口是public的,代理类默认是public final的,并且生成的代理类默认放到com.sun.proxy这个包下。
- 如果接口是非public的,那么代理类也是非public的,并且生成的代理类会放在对应接口所在的包下。
- 如果接口是非public的,并且这些接口不在同一个包下,那么就会报错。
sun.misc.ProxyGenerator.ProxyMethod#generateMethod
如果要持续深刻追寻 生成的 代理类 和 InvocationHandler
的invoke
的关系,持续往里看两层,就是了????
sun.misc.ProxyGenerator.ProxyMethod#generateMethod
是的,就是咱们生成字节码的罕用套路。
到这里,就齐全扣上了,再回头看 java实现的动静代理离不开这几个外围点
1、Proxy 2、InvocationHandler 3、反射技术
链接:https://juejin.cn/post/690406...