From d1706781828811e68210fdd99986fd1d6ca31398 Mon Sep 17 00:00:00 2001 From: tursom Date: Thu, 19 Jan 2023 18:59:59 +0800 Subject: [PATCH] faster proxy --- ts-core/ts-proxy/TestClass.class | Bin 0 -> 5266 bytes ts-core/ts-proxy/TestClass2.class | Bin 0 -> 6421 bytes .../TestClass_InvocationHandler.class | Bin 0 -> 3897 bytes ts-core/ts-proxy/TestClass_MethodAccess.class | Bin 0 -> 2435 bytes ts-core/ts-proxy/a | 0 ts-core/ts-proxy/build.gradle.kts | 1 + .../cn/tursom/proxy/ListProxyContainer.kt | 32 ---- .../cn/tursom/proxy/MutableProxyContainer.kt | 7 - .../src/main/kotlin/cn/tursom/proxy/Proxy.kt | 146 ++++++++++++++--- .../kotlin/cn/tursom/proxy/ProxyContainer.kt | 30 ---- .../kotlin/cn/tursom/proxy/ProxyDispatcher.kt | 12 -- .../cn/tursom/proxy/ProxyInterceptor.kt | 25 --- .../kotlin/cn/tursom/proxy/ProxyMethod.kt | 150 ------------------ .../cn/tursom/proxy/ProxyMethodCache.kt | 45 ------ .../kotlin/cn/tursom/proxy/ProxyResult.kt | 22 --- .../kotlin/cn/tursom/proxy/ProxyRunner.kt | 148 ----------------- .../tursom/proxy/annotation/ForFirstProxy.kt | 2 +- .../proxy/container/ListProxyContainer.kt | 54 +++++++ .../proxy/container/MutableProxyContainer.kt | 9 ++ .../tursom/proxy/container/ProxyContainer.kt | 14 ++ .../proxy/container/ProxyMethodCache.kt | 28 ++++ .../container/ProxyMethodCacheFunction.kt | 13 ++ .../function/CachedOnForEachProxyImpl.kt | 25 +++ .../CallSuperProxyMethodCacheFunction.kt | 18 +++ .../function/JavaReflectProxyMethodInvoker.kt | 61 +++++++ .../proxy/function/OnForEachProxyImpl.kt | 52 ++++++ .../proxy/function/OnForFirstProxyImpl.kt | 97 +++++++++++ .../cn/tursom/proxy/function/ProxyMethod.kt | 53 +++++++ .../proxy/function/ProxyMethodInvoker.kt | 21 +++ .../function/ReflectASMProxyMethodInvoker.kt | 48 ++++++ .../LocalCachedNoProxyInvocationHandler.kt | 42 +++++ .../LocalCachedProxyInterceptor.kt | 33 ++++ .../interceptor/NoProxyProxyInterceptor.kt | 13 ++ .../proxy/interceptor/ProxyInterceptor.kt | 59 +++++++ .../cn/tursom/proxy/{ => util}/CglibUtil.kt | 7 +- .../kotlin/cn/tursom/proxy/util/IntMap.kt | 42 +++++ .../test/kotlin/cn/tursom/proxy/Example.kt | 87 ++++++---- 37 files changed, 873 insertions(+), 523 deletions(-) create mode 100644 ts-core/ts-proxy/TestClass.class create mode 100644 ts-core/ts-proxy/TestClass2.class create mode 100644 ts-core/ts-proxy/TestClass_InvocationHandler.class create mode 100644 ts-core/ts-proxy/TestClass_MethodAccess.class create mode 100644 ts-core/ts-proxy/a delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ListProxyContainer.kt delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/MutableProxyContainer.kt delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyContainer.kt delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyDispatcher.kt delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyInterceptor.kt delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethod.kt delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethodCache.kt delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyResult.kt delete mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ListProxyContainer.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/MutableProxyContainer.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyContainer.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCache.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCacheFunction.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CachedOnForEachProxyImpl.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CallSuperProxyMethodCacheFunction.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JavaReflectProxyMethodInvoker.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForEachProxyImpl.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForFirstProxyImpl.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethod.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethodInvoker.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ReflectASMProxyMethodInvoker.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedNoProxyInvocationHandler.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedProxyInterceptor.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/NoProxyProxyInterceptor.kt create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/ProxyInterceptor.kt rename ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/{ => util}/CglibUtil.kt (90%) create mode 100644 ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/util/IntMap.kt diff --git a/ts-core/ts-proxy/TestClass.class b/ts-core/ts-proxy/TestClass.class new file mode 100644 index 0000000000000000000000000000000000000000..7c859f25ce917369df257bd760d7895b8f09a459 GIT binary patch literal 5266 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 literal 0 HcmV?d00001 diff --git a/ts-core/ts-proxy/TestClass2.class b/ts-core/ts-proxy/TestClass2.class new file mode 100644 index 0000000000000000000000000000000000000000..ccbb7f9d7273af009a92a7b7939e52d2702b1c99 GIT binary patch literal 6421 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 YF^$r6Me=FE3Pz2|DeFxmEf1dm0mj{5jQ{`u literal 0 HcmV?d00001 diff --git a/ts-core/ts-proxy/TestClass_InvocationHandler.class b/ts-core/ts-proxy/TestClass_InvocationHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..8a6534ad1d8bb54c68a09923161b14213a44ab25 GIT binary patch literal 3897 zcmb7G`*$1F5&o{_M6$9F+j(Ns#12ZZq{NC%pbaq(NtTI-VyBTDp(MqurE6Kqde^L0 zc~G7$Z)l-UTKeQs3>Xc{omK$ z0yuzA8ODlc%&FN`YazC1TNf_IQWx}vMT3WOyy_$ky;=>0Qs%sF7P+0cn0zFYPJ}`S z_mA!$IdE{!55_Qf%Lsn>82U`^#Hw?#V%ez7Dy#{;=vekeKh`m97%Ov=+q%O`57LuF zN=!{pjx(^6482k_5l`l(ju&Re>h?59n0*^4>z-VOa*(iK0nLZB{dN*awzPnr8GIDAtyoeYicRq`cY^Eo!6`L zNvp&|2PkO$LBlEO{R@WM zUJT2(#1AcVWT@Q<(l~Uy+&4O}zs=;Rd-(AOhCC(a?M^z`4|z2z(k(djglItTYKBc4 z1~2PI+%DG^xaoLW{?FpLvxp|UCeHi;({cvpteRO0;4dw+qu#yl{CYQtcknl2nTW5i zhhc!`)=fDg2P$>bVQ?sYQ+v@Ing^mPFv2${gFHMKP3yWs~+#YDD0k+YWG3DI4WQKvJv1hsd&1fcw8!;X(;%mOKuiD*nyoY zv#hHDVv#Q}SojWFK5`Aa#Y5yW?k3mpSBQ0D6(h?y@Y(ehjGdghiifVlM~=Jc?>;4e z=E^;|pJWf>NGN~;J&Wt!b^znFtZ>2Czk&%7_Hfn(yVL>`rB4L`Bcy?j$8QIpggb{W@gcKlQL=?z0PAHILE(EZ*9mr!IvQB>9vV>jq zl_r)Tq=-)6Y%2QcA6AOTJ<)$mDK_H?=+w=k3#V23;dbfs27ovBPIB2ve!EfBbj{>U-5e|`zwt9Uay z;~QN?^h*rNa16h}Z&f~bs&L)WYj}GF9hCU*7~OvE>V@U+mE~Q^avL?)9}B){_WK9l<9_g0x(0L6X)!{xNT?hRC2fI?S3;+NC literal 0 HcmV?d00001 diff --git a/ts-core/ts-proxy/TestClass_MethodAccess.class b/ts-core/ts-proxy/TestClass_MethodAccess.class new file mode 100644 index 0000000000000000000000000000000000000000..d66e971539733ff52aa67beee4be8155e91a0d2a GIT binary patch literal 2435 zcmbtV%~u;$6#qR)n3xVF&=1OoHNj{@DMl!@6|k73u|$GkiBv$v$z&1&!%WCbfYy(S z^=s+My~mv^-2{$3r*^BZ{1;rgb?fQzcwb&fCbY(Lbk6y`nRmb6z4zVu`L7@DqZPyW zf?--U!gi@>nVaE4(cHZij_)d)1ziiKG|P_Zie&|Zabry}RIM1j6}z5HM1#T0>9mp= zyD~bf*=uGdqNXF2PshENiQ zt>v_$ga8j9;j~$0RRVb0iva`~+^TLGWU#X0UG#Bg>cX=rxX%7)dPo=;bs zDyHaqT2VJ9B%EhBW@tMJ!?Jl(F^qj?(jK=E@vxL8kU?q&v3#?uj)w{ zWw=TH>Ln2xPD)kwKLs_$gSy1f*CYoLE;EdTnx^R=&io=bKTbUYq34Mc!L7rg-HC@G^reG%U@I1SvT#syN-YC}P~=HHLPiO*IgmEl$pBQKq%4FE6?5Ac!%q* zQZji~Whf$c6gj~q{}iesBSJeu3-lQ41!_Zxq6N4^V%Ig_E zwJ4x2Vcl<-wm)l@jLf*-gZGY1~W2c z`O@dbF4uL5$?93KX`Ia}1q9GSKP>*VfaWCHX#I?Ko%Ck(cAwve=X=h_9-e?#u-QWr zbp!0Dp$Cx1UH#wEH=**Jp>>O}NBErZCE+W=H-!6yUkJYvek1%&_=E5#>3a#CgaF|j zVTv$MSR&*ICBj_-*<)Y#xQ2ZgeSqU-bRFQ#cRj8$`YWsd0MArD25A*SLuG_(n~`B3 zBgKouz7~2B>xCNYN*NOs)vGnqKpBxT;;cfRuB = ArrayList(), -) : MutableProxyContainer { - override var lastModify: Long = System.currentTimeMillis() - private set - override val context: Context = ProxyContainer.contextEnv.newContext() - - override fun addProxy(proxy: ProxyMethod) { - lastModify = System.currentTimeMillis() - proxyList.add(proxy) - } - - override fun addAllProxy(proxy: Collection?): Boolean { - lastModify = System.currentTimeMillis() - return proxyList.addAll(proxy!!) - } - - override fun removeProxy(proxy: ProxyMethod) { - lastModify = System.currentTimeMillis() - proxyList.remove(proxy) - } - - override fun iterator(): MutableIterator { - lastModify = System.currentTimeMillis() - return proxyList.iterator() - } -} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/MutableProxyContainer.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/MutableProxyContainer.kt deleted file mode 100644 index 444d5be..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/MutableProxyContainer.kt +++ /dev/null @@ -1,7 +0,0 @@ -package cn.tursom.proxy - -interface MutableProxyContainer : ProxyContainer { - fun addProxy(proxy: ProxyMethod) - fun addAllProxy(proxy: Collection?): Boolean - fun removeProxy(proxy: ProxyMethod) -} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/Proxy.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/Proxy.kt index 23b9e61..30ab0f0 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/Proxy.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/Proxy.kt @@ -1,24 +1,27 @@ package cn.tursom.proxy +import cn.tursom.core.allMethodsSequence +import cn.tursom.core.isPrivate import cn.tursom.core.uncheckedCast -import net.sf.cglib.proxy.Enhancer -import net.sf.cglib.proxy.Factory +import cn.tursom.proxy.container.ListProxyContainer +import cn.tursom.proxy.container.MutableProxyContainer +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.function.ProxyMethod +import cn.tursom.proxy.interceptor.LocalCachedProxyInterceptor +import cn.tursom.proxy.interceptor.ProxyInterceptor +import cn.tursom.reflect.final +import net.sf.cglib.proxy.* import java.util.concurrent.ConcurrentHashMap object Proxy { - object CallSuperException : Exception() - - val callSuper = object : ThreadLocal() { - override fun initialValue(): Boolean = throw CallSuperException - override fun get(): Boolean = try { - super.get() - } catch (_: CallSuperException) { - false - } - } - var defaultContainer: () -> MutableProxyContainer = { ListProxyContainer() } private val cache = ConcurrentHashMap, Class<*>>() + val directAccessorKey = ProxyContainer.ctxEnv.newKey() + + private val methodProxyFieldSignature = MethodProxy::class.java.getDeclaredField("sig1").also { + it.isAccessible = true + it.final = false + } fun getContainer(obj: Any): ProxyContainer? { if (obj !is Factory) return null @@ -38,18 +41,88 @@ object Proxy { builder: (Class) -> T, ): Pair { val target = getCachedTarget(clazz) + + val directAccessor = builder(target) val obj = builder(target) - injectCallback(obj as Factory, container) + + container.target = obj + container.ctx[directAccessorKey] = directAccessor + + injectCallback(obj as Factory, container, directAccessor) + return obj to container } inline fun get() = get(T::class.java) - inline fun get( + inline operator fun get( argumentTypes: Array>, arguments: Array, container: MutableProxyContainer = defaultContainer(), ) = get(T::class.java, argumentTypes, arguments, container) + inline operator fun get( + a1: A1, + container: MutableProxyContainer = defaultContainer(), + ) = get(arrayOf(A1::class.java), arrayOf(a1), container) + + inline operator fun < + reified T : Any, + reified A1 : Any?, + reified A2 : Any?, + > get( + a1: A1, a2: A2, + container: MutableProxyContainer = defaultContainer(), + ) = get( + arrayOf(A1::class.java, A2::class.java), + arrayOf(a1, a2), + container, + ) + + inline operator fun < + reified T : Any, + reified A1 : Any?, + reified A2 : Any?, + reified A3 : Any?, + > get( + a1: A1, a2: A2, a3: A3, + container: MutableProxyContainer = defaultContainer(), + ) = get( + arrayOf(A1::class.java, A2::class.java, A3::class.java), + arrayOf(a1, a2, a3), + container, + ) + + inline operator fun < + reified T : Any, + reified A1 : Any?, + reified A2 : Any?, + reified A3 : Any?, + reified A4 : Any?, + > get( + a1: A1, a2: A2, a3: A3, a4: A4, + container: MutableProxyContainer = defaultContainer(), + ) = get( + arrayOf(A1::class.java, A2::class.java, A3::class.java, A4::class.java), + arrayOf(a1, a2, a3, a4), + container, + ) + + inline operator fun < + reified T : Any, + reified A1 : Any?, + reified A2 : Any?, + reified A3 : Any?, + reified A4 : Any?, + reified A5 : Any?, + > get( + a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, + container: MutableProxyContainer = defaultContainer(), + ) = get( + arrayOf(A1::class.java, A2::class.java, A3::class.java, A4::class.java, A5::class.java), + arrayOf(a1, a2, a3, a4, a5), + container, + ) + operator fun get(clazz: Class, container: MutableProxyContainer = defaultContainer()) = get(clazz, container, Class::newInstance) @@ -68,23 +141,56 @@ object Proxy { if (interfaces.isNotEmpty()) { enhancer.setInterfaces(interfaces) } - enhancer.setCallbackType(ProxyInterceptor::class.java) - enhancer.setCallbackFilter { 0 } + + val methods = clazz.allMethodsSequence.filter { !it.isPrivate() }.toList() + + enhancer.setCallbackTypes(Array(methods.size) { MethodInterceptor::class.java }) + enhancer.setCallbackFilter(methods::indexOf) + return enhancer } @JvmOverloads - fun injectCallback(obj: Any, container: ProxyContainer = defaultContainer()): ProxyContainer { + fun injectCallback(obj: Any, container: ProxyContainer = defaultContainer(), target: Any = obj): ProxyContainer { obj as Factory - if (obj.getCallback(0) != null && obj.getCallback(0) != ProxyDispatcher) { + if (obj.getCallback(0) != null && obj.getCallback(0) is ProxyInterceptor) { return (obj.getCallback(0) as ProxyInterceptor).container } - obj.setCallback(0, ProxyInterceptor(container)) + val nonProxyClasses: MutableSet> = HashSet(listOf(Any::class.java)) + repeat(obj.callbacks.size) { + obj.setCallback(it, LocalCachedProxyInterceptor(container, nonProxyClasses, target)) + } return container } fun getCachedTarget(clazz: Class): Class = cache.computeIfAbsent(clazz) { newEnhancer(clazz).createClass() }.uncheckedCast() + + fun getSuperCaller( + obj: T, + ): T = getContainer(obj)?.ctx?.get(directAccessorKey).uncheckedCast() + + fun addNonProxyClass(target: Any, nonProxyClass: Class<*>): Boolean { + if (target !is Factory || + target.getCallback(0) == null || + target.getCallback(0) !is ProxyInterceptor + ) { + throw IllegalArgumentException() + } + + return (target.getCallback(0) as ProxyInterceptor).nonProxyClasses.add(nonProxyClass) + } + + fun removeNonProxyClass(target: Any, nonProxyClass: Class<*>): Boolean { + if (target !is Factory || + target.getCallback(0) == null || + target.getCallback(0) !is ProxyInterceptor + ) { + throw IllegalArgumentException() + } + + return (target.getCallback(0) as ProxyInterceptor).nonProxyClasses.remove(nonProxyClass) + } } diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyContainer.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyContainer.kt deleted file mode 100644 index 1d0f0a4..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyContainer.kt +++ /dev/null @@ -1,30 +0,0 @@ -package cn.tursom.proxy - -import cn.tursom.core.context.ArrayContextEnv -import cn.tursom.core.context.Context - -interface ProxyContainer : Iterable { - companion object { - val contextEnv = ArrayContextEnv() - - inline fun ProxyContainer.forEachProxy(action: (ProxyMethod) -> Unit) { - for (t in this) { - action(t) - } - } - - inline fun ProxyContainer.forFirstProxy(action: (ProxyMethod) -> ProxyResult): ProxyResult { - for (t in this) { - val result = action(t) - if (result.success) { - return result - } - } - return ProxyResult.failed() - } - } - - // to impl, use override val context: Context = ProxyContainer.contextEnv.newContext() - val context: Context - val lastModify: Long -} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyDispatcher.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyDispatcher.kt deleted file mode 100644 index eec44db..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyDispatcher.kt +++ /dev/null @@ -1,12 +0,0 @@ -package cn.tursom.proxy - -import net.sf.cglib.proxy.MethodInterceptor -import net.sf.cglib.proxy.MethodProxy -import java.lang.reflect.Method - -object ProxyDispatcher : MethodInterceptor { - override fun intercept(obj: Any, method: Method, args: Array, proxy: MethodProxy): Any { - Proxy.injectCallback(obj) - return proxy(obj, args) - } -} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyInterceptor.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyInterceptor.kt deleted file mode 100644 index 9adb1ff..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyInterceptor.kt +++ /dev/null @@ -1,25 +0,0 @@ -package cn.tursom.proxy - -import net.sf.cglib.proxy.MethodInterceptor -import net.sf.cglib.proxy.MethodProxy -import java.lang.reflect.Method - -class ProxyInterceptor( - val container: ProxyContainer = ListProxyContainer(), - // disable call super can save 20% time - private val supportCallSuper: Boolean = true, -) : MethodInterceptor { - override fun intercept(obj: Any, method: Method, args: Array, proxy: MethodProxy): Any? { - if (supportCallSuper && Proxy.callSuper.get()) { - Proxy.callSuper.remove() - return proxy.invokeSuper(obj, args) - } - - val result = ProxyRunner.onProxy(obj, container, method, args, proxy) - return if (result.success) { - result.result - } else { - proxy.invokeSuper(obj, args) - } - } -} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethod.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethod.kt deleted file mode 100644 index bcfcc6d..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethod.kt +++ /dev/null @@ -1,150 +0,0 @@ -package cn.tursom.proxy - -import cn.tursom.proxy.annotation.ForEachProxy -import cn.tursom.proxy.annotation.ForFirstProxy -import cn.tursom.reflect.asm.ReflectAsmUtils -import com.esotericsoftware.reflectasm.MethodAccess -import net.sf.cglib.proxy.MethodProxy -import java.lang.reflect.Method -import java.util.concurrent.ConcurrentHashMap - -internal typealias ProxyMethodHandler = (proxy: ProxyMethod, args: Array) -> ProxyResult<*> - -interface ProxyMethod { - @Throws(Throwable::class) - fun onProxy( - ignored: Any, - c: ProxyContainer, - method: Method, - args: Array, - proxy: MethodProxy - ): ProxyResult<*> { - val handlerCacheMap = getHandlerCacheMap(javaClass) - val handlerCache = handlerCacheMap[method] - if (handlerCache != null) { - return if (handlerCache.success) { - handlerCache.result(this, args) - } else { - ProxyResult.failed() - } - } - - val reflectAsmHandler = ReflectASMProxyMethodInvoker[this, method, handlerCacheMap] - if (reflectAsmHandler != null) { - return reflectAsmHandler(this, args) - } - - val javaReflectHandler = JavaReflectProxyMethodInvoker[this, method, handlerCacheMap] - if (javaReflectHandler != null) { - javaReflectHandler(this, args) - } - - handlerCacheMap[method] = ProxyResult.failed() - return ProxyResult.failed() - } - - companion object { - private val handlerCacheMapMap: MutableMap< - Class, - MutableMap> - > = HashMap() - - fun getHandlerCacheMap(type: Class): MutableMap> { - var handlerCacheMap = handlerCacheMapMap[type] - if (handlerCacheMap == null) synchronized(handlerCacheMapMap) { - handlerCacheMap = handlerCacheMapMap[type] - if (handlerCacheMap == null) { - handlerCacheMap = ConcurrentHashMap() - handlerCacheMapMap[type] = handlerCacheMap!! - } - } - return handlerCacheMap!! - } - } -} - -private class ReflectASMProxyMethodInvoker( - val methodAccess: MethodAccess, - val index: Int, -) : ProxyMethodHandler { - companion object { - private val fastInvoker: MethodAccess.(Any, Int, Array) -> Any? = MethodAccess::invoke - - operator fun get( - proxy: ProxyMethod, - method: Method, - handlerCacheMap: MutableMap> - ): ProxyMethodHandler? { - val reflectAsmMethod = try { - ReflectAsmUtils.getMethod( - proxy.javaClass, - method.name, - paramTypes = method.parameterTypes, - returnType = method.returnType, - ) - } catch (e: Exception) { - e.printStackTrace() - null - } - if (reflectAsmMethod != null) { - val (methodAccess, index) = reflectAsmMethod - val invoker = ReflectASMProxyMethodInvoker(methodAccess, index) - handlerCacheMap[method] = ProxyResult.of(invoker) - return invoker - } - - return null - } - } - - override fun invoke(proxy: ProxyMethod, args: Array): ProxyResult<*> { - return ProxyResult.of(fastInvoker(methodAccess, proxy, index, args)) - } -} - -private class JavaReflectProxyMethodInvoker( - val method: Method, -) : ProxyMethodHandler { - companion object { - private val fastInvoker: Method.(Any, Array) -> Any? = Method::invoke - - operator fun get( - proxy: ProxyMethod, - method: Method, - handlerCacheMap: MutableMap> - ): ProxyMethodHandler? { - var invoker: ProxyMethodHandler? = null - - val selfMethod: Method - try { - var methodName = method.name - for (annotation in method.annotations) { - if (annotation is ForEachProxy) { - if (annotation.name.isNotEmpty()) { - methodName = annotation.name - break - } - } else if (annotation is ForFirstProxy) { - if (annotation.name.isNotEmpty()) { - methodName = annotation.name - break - } - } - } - selfMethod = proxy.javaClass.getMethod(methodName, *method.parameterTypes) - selfMethod.isAccessible = true - - invoker = JavaReflectProxyMethodInvoker(method) - - handlerCacheMap[method] = ProxyResult(invoker, true) - } catch (_: Exception) { - } - - return invoker - } - } - - override fun invoke(proxy: ProxyMethod, args: Array): ProxyResult<*> { - return ProxyResult.of(fastInvoker(method, proxy, args)) - } -} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethodCache.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethodCache.kt deleted file mode 100644 index bdb72b5..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyMethodCache.kt +++ /dev/null @@ -1,45 +0,0 @@ -package cn.tursom.proxy - -import net.sf.cglib.proxy.MethodProxy -import java.lang.reflect.Method -import java.util.concurrent.ConcurrentHashMap - -typealias ProxyMethodCacheFunction = ( - obj: Any, - c: ProxyContainer, - method: Method, - args: Array, - proxy: MethodProxy -) -> ProxyResult<*> - -class ProxyMethodCache( - private var lastModify: Long = 0, -) { - companion object { - val failed: ProxyMethodCacheFunction = { _, _, _, _, _ -> ProxyResult.failed } - } - - private val functionMap = ConcurrentHashMap() - - fun update(lastModify: Long, proxy: MethodProxy, function: ProxyMethodCacheFunction = functionMap[proxy] ?: failed) { - if (this.lastModify != lastModify) { - functionMap.clear() - } - - this.lastModify = lastModify - functionMap[proxy] = function - } - - operator fun invoke( - lastModify: Long, - obj: Any, - c: ProxyContainer, - method: Method, - args: Array, - proxy: MethodProxy, - ): ProxyResult<*>? = if (lastModify != this.lastModify) { - null - } else { - functionMap[proxy]?.invoke(obj, c, method, args, proxy) - } -} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyResult.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyResult.kt deleted file mode 100644 index 3c46557..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyResult.kt +++ /dev/null @@ -1,22 +0,0 @@ -package cn.tursom.proxy - -import cn.tursom.core.uncheckedCast - -data class ProxyResult( - val result: R, - val success: Boolean = false, -) { - companion object { - val success: ProxyResult<*> = ProxyResult(null, true) - val failed: ProxyResult<*> = ProxyResult(null, false) - - fun of(): ProxyResult = success.uncheckedCast() - fun of(result: R): ProxyResult = if (result == null) { - success.uncheckedCast() - } else { - ProxyResult(result, true) - } - - fun failed(): ProxyResult = failed.uncheckedCast() - } -} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt deleted file mode 100644 index d439896..0000000 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/ProxyRunner.kt +++ /dev/null @@ -1,148 +0,0 @@ -package cn.tursom.proxy - -import cn.tursom.proxy.ProxyContainer.Companion.forEachProxy -import cn.tursom.proxy.ProxyContainer.Companion.forFirstProxy -import cn.tursom.proxy.annotation.ForEachProxy -import cn.tursom.proxy.annotation.ForFirstProxy -import net.sf.cglib.proxy.MethodProxy -import org.apache.commons.lang3.StringUtils -import java.lang.reflect.Method -import java.util.* - - -object ProxyRunner { - private val errMsgSearchList = arrayOf("%M", "%B", "%A") - private val proxyMethodCacheKey = ProxyContainer.contextEnv.newKey() - .withDefault { ProxyMethodCache() } - - /** - * will be call when proxy method invoke. - * 在代理方法被调用时,该方法会被调用 - */ - @Throws(Throwable::class) - fun onProxy(obj: Any, c: ProxyContainer, method: Method, args: Array, proxy: MethodProxy): ProxyResult<*> { - val cache = c.context[proxyMethodCacheKey] - cache(c.lastModify, obj, c, method, args, proxy)?.let { - return it - } - - var handler: ProxyMethodCacheFunction? = null - for (annotation in method.annotations) when (annotation) { - is ForEachProxy -> { - handler = onForeachProxy(annotation) - break - } - is ForFirstProxy -> { - handler = onForFirstProxy(annotation) - break - } - } - if (handler == null) { - //handler = ProxyContainerHandlerCache.callSuper - handler = onForFirstProxy(ForFirstProxy.EMPTY) - } - return handler(obj, c, method, args, proxy) - } - - fun onForFirstProxy(forFirstProxy: ForFirstProxy): ProxyMethodCacheFunction { - val classes = when (forFirstProxy.value.size) { - 0 -> emptyList() - 1 -> listOf(forFirstProxy.value[0].java) - else -> forFirstProxy.value.asSequence().map { it.java }.toSet() - } - return { o, c, m: Method, a, p -> - onForFirstProxy(o, c, m, a, p, forFirstProxy, classes) - } - } - - private fun onForFirstProxy( - obj: Any, - container: ProxyContainer, - method: Method, - args: Array, - proxy: MethodProxy, - forFirstProxy: ForFirstProxy, - classes: Collection>, - ): ProxyResult<*> { - val result = container.forFirstProxy { p -> - if (classes.isEmpty() || classes.stream().anyMatch { c: Class<*> -> c.isInstance(p) }) { - val result = p.onProxy(obj, container, method, args, proxy) - if (forFirstProxy.cache && result.success) { - container.context[proxyMethodCacheKey].update(container.lastModify, proxy, p::onProxy) - } - return@forFirstProxy result - } else { - return@forFirstProxy ProxyResult.failed - } - } - if (result.success) { - return result - } - - // when request not handled - if (forFirstProxy.must) { - // generate error message - var errMsg: String = forFirstProxy.errMsg - if (errMsg.isBlank()) { - errMsg = "no proxy handled on method %M" - } - val replacementList = arrayOfNulls(errMsgSearchList.size) - // todo use efficient contains - if (errMsg.contains(errMsgSearchList[0])) { - replacementList[0] = method.toString() - } - if (errMsg.contains(errMsgSearchList[1])) { - replacementList[1] = obj.toString() - } - if (errMsg.contains(errMsgSearchList[2])) { - replacementList[2] = Arrays.toString(args) - } - - errMsg = StringUtils.replaceEach(errMsg, errMsgSearchList, replacementList) - val exceptionConstructor = forFirstProxy.errClass.java.getConstructor(String::class.java) - if (forFirstProxy.cache) { - container.context[proxyMethodCacheKey].update(container.lastModify, proxy) { _, _, _, _, _ -> - throw exceptionConstructor.newInstance(errMsg) - } - } - throw exceptionConstructor.newInstance(errMsg) - } - if (forFirstProxy.cache) { - container.context[proxyMethodCacheKey].update(container.lastModify, proxy) - } - return ProxyResult.failed - } - - fun onForeachProxy(forEachProxy: ForEachProxy) = onForeachProxy(when (forEachProxy.value.size) { - 0 -> emptyList() - 1 -> listOf(forEachProxy.value[0].java) - else -> forEachProxy.value.asSequence().map { it.java }.toSet() - }, forEachProxy.cache) - - private val emptyProxyList = ArrayList() - private fun onForeachProxy( - classes: Collection>, - cache: Boolean, - ): ProxyMethodCacheFunction = { o, c, m, a, proxy -> - val proxyList = if (cache) ArrayList() else emptyProxyList - c.forEachProxy { p -> - if (classes.isEmpty() || classes.any { c: Class<*> -> c.isInstance(p) }) { - val result = p.onProxy(o, c, m, a, proxy) - if (cache && result.success) { - proxyList.add(p) - } - } - } - if (cache) { - c.context[proxyMethodCacheKey].update(c.lastModify, proxy, onCachedForeachProxy((proxyList))) - } - ProxyResult.failed() - } - - private fun onCachedForeachProxy(proxyList: List): ProxyMethodCacheFunction = { o, c, m, a, proxy -> - proxyList.forEach { p -> - p.onProxy(o, c, m, a, proxy) - } - ProxyResult.failed() - } -} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/annotation/ForFirstProxy.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/annotation/ForFirstProxy.kt index 36122ce..355d26e 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/annotation/ForFirstProxy.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/annotation/ForFirstProxy.kt @@ -13,7 +13,7 @@ annotation class ForFirstProxy( */ val must: Boolean = false, val errMsg: String = "", - val errClass: KClass = RuntimeException::class, + val errClass: KClass = Throwable::class, val cache: Boolean = true, ) { companion object { diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ListProxyContainer.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ListProxyContainer.kt new file mode 100644 index 0000000..5707c58 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ListProxyContainer.kt @@ -0,0 +1,54 @@ +package cn.tursom.proxy.container + +import cn.tursom.core.context.Context +import cn.tursom.proxy.function.ProxyMethod +import cn.tursom.proxy.util.CglibUtil +import net.sf.cglib.proxy.MethodProxy + + +class ListProxyContainer( + private val proxyList: MutableCollection = ArrayList(), +) : MutableProxyContainer { + override lateinit var target: Any + override val ctx: Context = ProxyContainer.ctxEnv.newContext() + + private fun clearCache() { + ctx[ProxyMethodCache.ctxKey].clear() + } + + override fun addProxy(proxy: Any) { + clearCache() + + proxyList.add(proxy) + if (proxy is ProxyMethod) { + proxy.onProxyAdded(this) + } + + clearCache() + } + + override fun addAllProxy(proxy: Collection?) { + clearCache() + + if (proxyList.addAll(proxy!!)) proxy.forEach { + if (it !is ProxyMethod) return@forEach + it.onProxyAdded(this) + } + + clearCache() + } + + override fun removeProxy(proxy: Any) { + clearCache() + + if (proxyList.remove(proxy) && proxy is ProxyMethod) { + proxy.onProxyRemoved(this) + } + + clearCache() + } + + override fun iterator(): Iterator { + return proxyList.iterator() + } +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/MutableProxyContainer.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/MutableProxyContainer.kt new file mode 100644 index 0000000..2c87c43 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/MutableProxyContainer.kt @@ -0,0 +1,9 @@ +package cn.tursom.proxy.container + +interface MutableProxyContainer : ProxyContainer { + override var target: Any + + fun addProxy(proxy: Any) + fun addAllProxy(proxy: Collection?) + fun removeProxy(proxy: Any) +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyContainer.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyContainer.kt new file mode 100644 index 0000000..75a8641 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyContainer.kt @@ -0,0 +1,14 @@ +package cn.tursom.proxy.container + +import cn.tursom.core.context.ArrayContextEnv +import cn.tursom.core.context.Context + +interface ProxyContainer : Iterable { + companion object { + val ctxEnv = ArrayContextEnv() + } + + // to impl, use override val context: Context = ProxyContainer.contextEnv.newContext() + val ctx: Context + val target: Any +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCache.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCache.kt new file mode 100644 index 0000000..ced0d22 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCache.kt @@ -0,0 +1,28 @@ +package cn.tursom.proxy.container + +import cn.tursom.proxy.util.IntMap +import net.sf.cglib.proxy.MethodProxy + +class ProxyMethodCache { + companion object { + val ctxKey = ProxyContainer.ctxEnv.newKey() + .withDefault { ProxyMethodCache() } + } + + //private val functionMap = HashMap() + private val functionMap = IntMap() + + fun clear() { + synchronized(functionMap) { + functionMap.clear() + } + } + + fun update(proxy: MethodProxy, function: ProxyMethodCacheFunction) { + synchronized(this) { + functionMap[proxy.superIndex] = function + } + } + + operator fun get(proxy: MethodProxy) = functionMap[proxy.superIndex] +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCacheFunction.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCacheFunction.kt new file mode 100644 index 0000000..e5c9fbd --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/container/ProxyMethodCacheFunction.kt @@ -0,0 +1,13 @@ +package cn.tursom.proxy.container + +import cn.tursom.proxy.container.ProxyContainer +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +fun interface ProxyMethodCacheFunction : ( + Any?, + ProxyContainer, + Method?, + Array?, + MethodProxy?, +) -> Any? diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CachedOnForEachProxyImpl.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CachedOnForEachProxyImpl.kt new file mode 100644 index 0000000..1e56739 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CachedOnForEachProxyImpl.kt @@ -0,0 +1,25 @@ +package cn.tursom.proxy.function + +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +class CachedOnForEachProxyImpl( + private val proxyList: List, +) : ProxyMethodCacheFunction { + override fun invoke( + o: Any?, + c: ProxyContainer, + m: Method?, + a: Array?, + proxy: MethodProxy?, + ): Any? { + proxy!! + + proxyList.forEach { p -> + p(o, c, m, a, proxy) + } + return proxy.invokeSuper(o, a) + } +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CallSuperProxyMethodCacheFunction.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CallSuperProxyMethodCacheFunction.kt new file mode 100644 index 0000000..db4181e --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/CallSuperProxyMethodCacheFunction.kt @@ -0,0 +1,18 @@ +package cn.tursom.proxy.function + +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +object CallSuperProxyMethodCacheFunction : ProxyMethodCacheFunction { + override fun invoke( + obj: Any?, + c: ProxyContainer, + method: Method?, + args: Array?, + proxy: MethodProxy?, + ): Any? { + return proxy!!.invokeSuper(obj, args) + } +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JavaReflectProxyMethodInvoker.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JavaReflectProxyMethodInvoker.kt new file mode 100644 index 0000000..1ae879c --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/JavaReflectProxyMethodInvoker.kt @@ -0,0 +1,61 @@ +package cn.tursom.proxy.function + +import cn.tursom.proxy.annotation.ForEachProxy +import cn.tursom.proxy.annotation.ForFirstProxy +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +internal class JavaReflectProxyMethodInvoker( + private val self: Any, + private val method: Method, +) : ProxyMethodCacheFunction { + companion object { + private val fastInvoker: Method.(Any?, Array?) -> Any? = Method::invoke + + operator fun get( + proxy: Any, + method: Method, + ): JavaReflectProxyMethodInvoker? { + var invoker: JavaReflectProxyMethodInvoker? = null + + val selfMethod: Method + try { + var methodName = method.name + for (annotation in method.annotations) { + if (annotation is ForEachProxy) { + if (annotation.name.isNotEmpty()) { + methodName = annotation.name + break + } + } else if (annotation is ForFirstProxy) { + if (annotation.name.isNotEmpty()) { + methodName = annotation.name + break + } + } + } + selfMethod = proxy.javaClass.getMethod(methodName, *method.parameterTypes) + selfMethod.isAccessible = true + + invoker = JavaReflectProxyMethodInvoker(proxy, method) + + //handlerCacheMap[method] = ProxyResult(invoker, true) + } catch (_: Exception) { + } + + return invoker + } + } + + override fun invoke( + obj: Any?, + c: ProxyContainer, + method: Method?, + args: Array?, + proxy: MethodProxy?, + ): Any? { + return fastInvoker(this.method, self, args) + } +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForEachProxyImpl.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForEachProxyImpl.kt new file mode 100644 index 0000000..7e9958c --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForEachProxyImpl.kt @@ -0,0 +1,52 @@ +package cn.tursom.proxy.function + +import cn.tursom.proxy.annotation.ForEachProxy +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCache +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +class OnForEachProxyImpl( + forEachProxy: ForEachProxy, +) : ProxyMethodCacheFunction { + companion object { + private val emptyProxyList = ArrayList() + } + + private val classes: Collection> = when (forEachProxy.value.size) { + 0 -> emptyList() + 1 -> listOf(forEachProxy.value[0].java) + else -> forEachProxy.value.asSequence().map { it.java }.toSet() + } + + private val cache: Boolean = forEachProxy.cache + + override fun invoke( + o: Any?, + c: ProxyContainer, + m: Method?, + a: Array?, + proxy: MethodProxy?, + ): Any? { + m!! + proxy!! + + val proxyList = if (cache) ArrayList() else emptyProxyList + c.forEach { p -> + if (classes.isEmpty() || classes.any { c: Class<*> -> c.isInstance(p) }) { + val handler = ProxyMethod.getHandler(p, m) ?: return@forEach + handler(o, c, m, a, proxy) + if (cache) { + proxyList.add(handler) + } + } + } + if (cache) { + c.ctx[ProxyMethodCache.ctxKey].update( + proxy, CachedOnForEachProxyImpl(proxyList) + ) + } + return proxy.invokeSuper(o, a) + } +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForFirstProxyImpl.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForFirstProxyImpl.kt new file mode 100644 index 0000000..4f1b716 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/OnForFirstProxyImpl.kt @@ -0,0 +1,97 @@ +package cn.tursom.proxy.function + +import cn.tursom.proxy.annotation.ForFirstProxy +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCache +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.MethodProxy +import org.apache.commons.lang3.StringUtils +import java.lang.reflect.Constructor +import java.lang.reflect.Method +import java.util.* + +class OnForFirstProxyImpl( + private val ffpAnnotation: ForFirstProxy, +) : ProxyMethodCacheFunction { + companion object { + private val errMsgSearchList = arrayOf("%M", "%B", "%A") + } + + private val classes: Collection> = when (ffpAnnotation.value.size) { + 0 -> emptyList() + 1 -> listOf(ffpAnnotation.value[0].java) + else -> ffpAnnotation.value.asSequence().map { it.java }.toSet() + } + + override fun invoke( + obj: Any?, + container: ProxyContainer, + method: Method?, + args: Array?, + proxy: MethodProxy?, + ): Any? { + method!! + proxy!! + + container.forEach { p -> + if (classes.isNotEmpty() && classes.none { c: Class<*> -> c.isInstance(p) }) { + return@forEach + } + + val handler = ProxyMethod.getHandler(p, method) ?: return@forEach + if (ffpAnnotation.cache) { + container.ctx[ProxyMethodCache.ctxKey].update(proxy, handler) + } + return handler(obj, container, method, args, proxy) + } + + // when request not handled + if (ffpAnnotation.must) { + // generate error message + var errMsg: String = ffpAnnotation.errMsg + if (errMsg.isBlank()) { + errMsg = "no proxy handled on method %M" + } + val replacementList = arrayOfNulls(errMsgSearchList.size) + // todo use efficient contains + if (errMsg.contains(errMsgSearchList[0])) { + replacementList[0] = method.toString() + } + if (errMsg.contains(errMsgSearchList[1])) { + replacementList[1] = obj.toString() + } + if (errMsg.contains(errMsgSearchList[2])) { + replacementList[2] = Arrays.toString(args) + } + + errMsg = StringUtils.replaceEach(errMsg, errMsgSearchList, replacementList) + val exceptionConstructor = ffpAnnotation.errClass.java.getConstructor(String::class.java) + if (ffpAnnotation.cache) { + container.ctx[ProxyMethodCache.ctxKey].update( + proxy, ExceptionProxyMethodCacheFunctionImpl(exceptionConstructor, errMsg) + ) + } + throw exceptionConstructor.newInstance(errMsg) + } + if (ffpAnnotation.cache) { + container.ctx[ProxyMethodCache.ctxKey].update( + proxy, + CallSuperProxyMethodCacheFunction, + ) + } + return proxy.invokeSuper(obj, args) + } +} + +private class ExceptionProxyMethodCacheFunctionImpl( + private val exceptionConstructor: Constructor, + private val errMsg: String, +) : ProxyMethodCacheFunction { + override fun invoke( + obj: Any?, + c: ProxyContainer, + method: Method?, + args: Array?, + proxy: MethodProxy?, + ) = throw exceptionConstructor.newInstance(errMsg) +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethod.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethod.kt new file mode 100644 index 0000000..de873bd --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethod.kt @@ -0,0 +1,53 @@ +package cn.tursom.proxy.function + +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +interface ProxyMethod { + fun onProxyAdded(container: ProxyContainer) { + // NO-OP + } + + fun onProxyRemoved(container: ProxyContainer) { + // NO-OP + } + + fun onProxyInvoke( + o: Any?, + c: ProxyContainer, + m: Method?, + a: Array?, + proxy: MethodProxy?, + next: ProxyMethodCacheFunction, + ): Any? { + return next(o, c, m, a, proxy) + } + + companion object { + fun getHandler(proxy: Any, method: Method): ProxyMethodCacheFunction? { + var handler = getReflectHandler(proxy, method) ?: return null + + if (proxy is ProxyMethod) { + handler = ProxyMethodInvoker(proxy, handler) + } + + return handler + } + + private fun getReflectHandler(proxy: Any, method: Method): ProxyMethodCacheFunction? { + val reflectAsmHandler = ReflectASMProxyMethodInvoker[proxy, method] + if (reflectAsmHandler != null) { + return reflectAsmHandler + } + + val javaReflectHandler = JavaReflectProxyMethodInvoker[proxy, method] + if (javaReflectHandler != null) { + return javaReflectHandler + } + + return null + } + } +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethodInvoker.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethodInvoker.kt new file mode 100644 index 0000000..e25c830 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ProxyMethodInvoker.kt @@ -0,0 +1,21 @@ +package cn.tursom.proxy.function + +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +internal class ProxyMethodInvoker( + private val proxyMethod: ProxyMethod, + private val next: ProxyMethodCacheFunction, +) : ProxyMethodCacheFunction { + override fun invoke( + obj: Any?, + c: ProxyContainer, + method: Method?, + args: Array?, + proxy: MethodProxy?, + ): Any? { + return proxyMethod.onProxyInvoke(obj, c, method, args, proxy, next) + } +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ReflectASMProxyMethodInvoker.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ReflectASMProxyMethodInvoker.kt new file mode 100644 index 0000000..a7d202b --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/function/ReflectASMProxyMethodInvoker.kt @@ -0,0 +1,48 @@ +package cn.tursom.proxy.function + +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import cn.tursom.reflect.asm.ReflectAsmUtils +import com.esotericsoftware.reflectasm.MethodAccess +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +internal class ReflectASMProxyMethodInvoker( + private val self: Any, + private val methodAccess: MethodAccess, + private val index: Int, +) : ProxyMethodCacheFunction { + companion object { + private val fastInvoker: MethodAccess.(Any, Int, Array?) -> Any? = MethodAccess::invoke + + operator fun get( + proxy: Any, + method: Method, + ): ReflectASMProxyMethodInvoker? { + val reflectAsmMethod = try { + ReflectAsmUtils.getMethod( + proxy.javaClass, + method.name, + paramTypes = method.parameterTypes, + returnType = method.returnType, + ) + } catch (e: Exception) { + e.printStackTrace() + null + } ?: return null + + val (methodAccess, index) = reflectAsmMethod + return ReflectASMProxyMethodInvoker(proxy, methodAccess, index) + } + } + + override fun invoke( + obj: Any?, + c: ProxyContainer, + method: Method?, + args: Array?, + proxy: MethodProxy?, + ): Any? { + return fastInvoker(methodAccess, self, index, args) + } +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedNoProxyInvocationHandler.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedNoProxyInvocationHandler.kt new file mode 100644 index 0000000..5808e38 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedNoProxyInvocationHandler.kt @@ -0,0 +1,42 @@ +package cn.tursom.proxy.interceptor + +import cn.tursom.reflect.asm.ReflectAsmUtils +import com.esotericsoftware.reflectasm.MethodAccess +import net.sf.cglib.proxy.InvocationHandler +import java.lang.reflect.Method + +class LocalCachedNoProxyInvocationHandler( + val proxy: Any, +) : InvocationHandler { + companion object { + private val fastInvoker: MethodAccess.(Any, Int, Array?) -> Any? = MethodAccess::invoke + } + + private var handler: (method: Method?, args: Array?) -> Any? = DefaultHandler() + + override fun invoke(ignore: Any, method: Method?, args: Array?): Any? { + return handler(method, args) + } + + private inner class DefaultHandler : (Method?, Array?) -> Any? { + override fun invoke(method: Method?, args: Array?): Any? { + method!! + + val (methodAccess, index) = ReflectAsmUtils.getMethodByRegex( + proxy.javaClass, + "CGLIB\\\$${method.name}\\\$.*".toRegex(), + *method.parameterTypes, + method.returnType, + )!! + handler = MethodAccessHandler(methodAccess, index) + return fastInvoker(methodAccess, proxy, index, args) + } + } + + private inner class MethodAccessHandler( + private val methodAccess: MethodAccess, + private val index: Int, + ) : (Method?, Array?) -> Any? { + override fun invoke(method: Method?, args: Array?) = fastInvoker(methodAccess, proxy, index, args) + } +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedProxyInterceptor.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedProxyInterceptor.kt new file mode 100644 index 0000000..c29d359 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/LocalCachedProxyInterceptor.kt @@ -0,0 +1,33 @@ +package cn.tursom.proxy.interceptor + +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCache +import cn.tursom.proxy.container.ProxyMethodCacheFunction +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +class LocalCachedProxyInterceptor( + container: ProxyContainer, + nonProxyClasses: MutableSet>, + val target: Any, +) : ProxyInterceptor(container, nonProxyClasses) { + private var cache: ProxyMethodCacheFunction? = null + + override fun intercept(obj: Any?, method: Method?, args: Array?, proxy: MethodProxy): Any? { + var cache = this.cache + + if (cache != null) { + return cache(target, container, method, args, proxy) + } + + val methodCache = container.ctx[ProxyMethodCache.ctxKey] + this.cache = methodCache[proxy] + cache = this.cache + + if (cache != null) { + return cache(target, container, method, args, proxy) + } + + return super.intercept(target, method, args, proxy) + } +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/NoProxyProxyInterceptor.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/NoProxyProxyInterceptor.kt new file mode 100644 index 0000000..fc04eb2 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/NoProxyProxyInterceptor.kt @@ -0,0 +1,13 @@ +package cn.tursom.proxy.interceptor + +import net.sf.cglib.proxy.MethodInterceptor +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +class NoProxyProxyInterceptor( + private val target: Any, +) : MethodInterceptor { + override fun intercept(obj: Any?, method: Method?, args: Array?, proxy: MethodProxy): Any? { + return proxy.invokeSuper(target, args) + } +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/ProxyInterceptor.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/ProxyInterceptor.kt new file mode 100644 index 0000000..3086a09 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/interceptor/ProxyInterceptor.kt @@ -0,0 +1,59 @@ +package cn.tursom.proxy.interceptor + +import cn.tursom.proxy.annotation.ForEachProxy +import cn.tursom.proxy.annotation.ForFirstProxy +import cn.tursom.proxy.container.ListProxyContainer +import cn.tursom.proxy.container.ProxyContainer +import cn.tursom.proxy.container.ProxyMethodCache +import cn.tursom.proxy.function.CallSuperProxyMethodCacheFunction +import cn.tursom.proxy.function.OnForEachProxyImpl +import cn.tursom.proxy.function.OnForFirstProxyImpl +import net.sf.cglib.proxy.MethodInterceptor +import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Method + +open class ProxyInterceptor( + val container: ProxyContainer = ListProxyContainer(), + val nonProxyClasses: MutableSet> = HashSet(listOf(Any::class.java)), +) : MethodInterceptor { + override fun intercept(obj: Any?, method: Method?, args: Array?, proxy: MethodProxy): Any? { + val cache = container.ctx[ProxyMethodCache.ctxKey] + var handler = cache[proxy] + if (handler != null) { + return handler(obj, container, method, args, proxy) + } + + method!! + + nonProxyClasses.forEach { nonProxyClass -> + nonProxyClass.declaredMethods.forEach { + if (it.name == method.name && + it.returnType.isAssignableFrom(method.returnType) && + it.parameterTypes.contentEquals(method.parameterTypes) + ) { + cache.update(proxy, CallSuperProxyMethodCacheFunction) + return proxy.invokeSuper(obj, args) + } + } + } + + //var handler: ProxyMethodCacheFunction? = null + + for (annotation in method.annotations) when (annotation) { + is ForEachProxy -> { + handler = OnForEachProxyImpl(annotation) + break + } + + is ForFirstProxy -> { + handler = OnForFirstProxyImpl(annotation) + break + } + } + if (handler == null) { + handler = OnForFirstProxyImpl(ForFirstProxy.EMPTY) + } + + return handler(obj, container, method, args, proxy) + } +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/CglibUtil.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/util/CglibUtil.kt similarity index 90% rename from ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/CglibUtil.kt rename to ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/util/CglibUtil.kt index a336678..8be90b3 100644 --- a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/CglibUtil.kt +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/util/CglibUtil.kt @@ -1,9 +1,12 @@ -package cn.tursom.proxy +package cn.tursom.proxy.util +import cn.tursom.core.final +import cn.tursom.core.static import cn.tursom.reflect.asm.ReflectAsmUtils import net.sf.cglib.core.Signature import net.sf.cglib.proxy.Callback import net.sf.cglib.proxy.MethodProxy +import java.lang.reflect.Field object CglibUtil { fun getFactoryData(clazz: Class<*>): Any? { @@ -37,4 +40,4 @@ object CglibUtil { "CGLIB\$SET_STATIC_CALLBACKS" )!!(callbacks) } -} \ No newline at end of file +} diff --git a/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/util/IntMap.kt b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/util/IntMap.kt new file mode 100644 index 0000000..55e9450 --- /dev/null +++ b/ts-core/ts-proxy/src/main/kotlin/cn/tursom/proxy/util/IntMap.kt @@ -0,0 +1,42 @@ +package cn.tursom.proxy.util + +import cn.tursom.core.uncheckedCast + +class IntMap { + companion object { + private fun upToPowerOf2(n: Int): Int { + if (n and n - 1 == 0) { + return n + } + + var n = n + n = n or (n ushr 1) + n = n or (n ushr 2) + n = n or (n ushr 4) + n = n or (n ushr 8) + n = n or (n ushr 16) + + return n + 1 + } + } + + private var array = arrayOfNulls(32) + + fun clear() { + array = arrayOfNulls(16) + } + + operator fun get(index: Int): V? = if (index >= array.size) { + null + } else { + array[index].uncheckedCast() + } + + operator fun set(index: Int, value: V) { + if (index >= array.size) { + array = array.copyOf(upToPowerOf2(index + 1)) + } + + array[index] = value + } +} \ No newline at end of file diff --git a/ts-core/ts-proxy/src/test/kotlin/cn/tursom/proxy/Example.kt b/ts-core/ts-proxy/src/test/kotlin/cn/tursom/proxy/Example.kt index 236350d..967fede 100644 --- a/ts-core/ts-proxy/src/test/kotlin/cn/tursom/proxy/Example.kt +++ b/ts-core/ts-proxy/src/test/kotlin/cn/tursom/proxy/Example.kt @@ -1,57 +1,86 @@ package cn.tursom.proxy +import cn.tursom.core.allFieldsSequence +import cn.tursom.core.static +import com.esotericsoftware.reflectasm.MethodAccess +import net.sf.cglib.proxy.InvocationHandler +import net.sf.cglib.proxy.MethodProxy import org.junit.Test import org.objectweb.asm.ClassWriter import java.io.File class Example { + companion object{ + var bytes: ByteArray? = null + + fun saveBytes(b: ByteArray) { + bytes = b + } + } + open class TestClass protected constructor() { - //@get:ForEachProxy open var a: Int = 0 } class GetA( - private val t: TestClass, - ) : ProxyMethod { - fun getA(): Int { - Proxy.callSuper.set(true) - return t.a + 1 - } + t: TestClass, + ) { + val t: TestClass = Proxy.getSuperCaller(t) + + val a: Int + get() = t.a + 1 + + //fun getA(): Int { + // return t.a + 1 + //} } @Test fun getClass() { + val access = MethodAccess.get(TestClass::class.java) + println(access) + val writer = ClassWriter(0) val enhancer = Proxy.newEnhancer(TestClass::class.java) + + enhancer.setCallbackType(InvocationHandler::class.java) + enhancer.setCallbackFilter { 0 } + val clazz = enhancer.createClass() - CglibUtil.setStaticCallbacks(clazz, arrayOf(ProxyInterceptor())) - val instance = clazz.newInstance() + //CglibUtil.setStaticCallbacks(clazz, arrayOf(ProxyInterceptor())) + //val instance = clazz.newInstance() enhancer.generateClass(writer) - File("TestClass.class").writeBytes(writer.toByteArray()) + File("TestClass_InvocationHandler.class").writeBytes(writer.toByteArray()) + clazz.allFieldsSequence.forEach { + if (!it.static) return@forEach + + it.isAccessible = true + println("${it.name} = ${it[null]}") + + if (it.type == MethodProxy::class.java) { + val methodProxy = it[null] as MethodProxy + println(methodProxy.signature) + println(methodProxy.superName) + println(methodProxy.superIndex) + } + } + } + + @Test + fun getMethodAccessClass() { + val (t, container) = Proxy.get() + + MethodAccess.get(t.javaClass)!! + //File("TestClass_MethodAccess.class").writeBytes(bytes!!) } @Test fun test() { - //val enhancer = Enhancer() - //enhancer.setSuperclass(TestClass::class.java) - //enhancer.setCallback(ProxyDispatcher) - //val t = enhancer.create() as TestClass - //val enhancer = Enhancer() - //enhancer.setSuperclass(TestClass::class.java) - //enhancer.setCallback(ProxyRefDispatcher { - // println("on Dispatcher") - // ProxyInterceptor() - //}) - // - //val t = enhancer.create() as TestClass - //val writer = ClassWriter(0) - //enhancer.generateClass(writer) - //File("TestClass_ProxyRefDispatcher.class").writeBytes(writer.toByteArray()) val (t, container) = Proxy.get() - //val t = Proxy.getCachedTarget(TestClass::class.java).newInstance() - //val container = Proxy.injectCallback(t) - //container as MutableProxyContainer - container.addProxy(GetA(t)) + val getA = GetA(t) + println(getA.t == t) + + container.addProxy(getA) println(t.javaClass) repeat(10) {