mirror of
https://github.com/tursom/TursomServer.git
synced 2025-03-13 19:30:10 +08:00
faster proxy
This commit is contained in:
parent
acf16136a4
commit
d170678182
BIN
ts-core/ts-proxy/TestClass.class
Normal file
BIN
ts-core/ts-proxy/TestClass.class
Normal file
Binary file not shown.
BIN
ts-core/ts-proxy/TestClass2.class
Normal file
BIN
ts-core/ts-proxy/TestClass2.class
Normal file
Binary file not shown.
BIN
ts-core/ts-proxy/TestClass_InvocationHandler.class
Normal file
BIN
ts-core/ts-proxy/TestClass_InvocationHandler.class
Normal file
Binary file not shown.
BIN
ts-core/ts-proxy/TestClass_MethodAccess.class
Normal file
BIN
ts-core/ts-proxy/TestClass_MethodAccess.class
Normal file
Binary file not shown.
0
ts-core/ts-proxy/a
Normal file
0
ts-core/ts-proxy/a
Normal file
@ -11,6 +11,7 @@ dependencies {
|
|||||||
api(project(":ts-core"))
|
api(project(":ts-core"))
|
||||||
api(project(":ts-core:ts-reflectasm"))
|
api(project(":ts-core:ts-reflectasm"))
|
||||||
api(group = "cglib", name = "cglib", version = "3.3.0")
|
api(group = "cglib", name = "cglib", version = "3.3.0")
|
||||||
|
implementation(group = "net.bytebuddy", name = "byte-buddy", version = "1.12.22")
|
||||||
implementation(group = "org.apache.commons", name = "commons-lang3", version = "3.8.1")
|
implementation(group = "org.apache.commons", name = "commons-lang3", version = "3.8.1")
|
||||||
testApi(group = "junit", name = "junit", version = "4.13.2")
|
testApi(group = "junit", name = "junit", version = "4.13.2")
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package cn.tursom.proxy
|
|
||||||
|
|
||||||
import cn.tursom.core.context.Context
|
|
||||||
|
|
||||||
|
|
||||||
class ListProxyContainer(
|
|
||||||
private val proxyList: MutableCollection<ProxyMethod> = 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<ProxyMethod>?): Boolean {
|
|
||||||
lastModify = System.currentTimeMillis()
|
|
||||||
return proxyList.addAll(proxy!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeProxy(proxy: ProxyMethod) {
|
|
||||||
lastModify = System.currentTimeMillis()
|
|
||||||
proxyList.remove(proxy)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator(): MutableIterator<ProxyMethod> {
|
|
||||||
lastModify = System.currentTimeMillis()
|
|
||||||
return proxyList.iterator()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
package cn.tursom.proxy
|
|
||||||
|
|
||||||
interface MutableProxyContainer : ProxyContainer {
|
|
||||||
fun addProxy(proxy: ProxyMethod)
|
|
||||||
fun addAllProxy(proxy: Collection<ProxyMethod>?): Boolean
|
|
||||||
fun removeProxy(proxy: ProxyMethod)
|
|
||||||
}
|
|
@ -1,24 +1,27 @@
|
|||||||
package cn.tursom.proxy
|
package cn.tursom.proxy
|
||||||
|
|
||||||
|
import cn.tursom.core.allMethodsSequence
|
||||||
|
import cn.tursom.core.isPrivate
|
||||||
import cn.tursom.core.uncheckedCast
|
import cn.tursom.core.uncheckedCast
|
||||||
import net.sf.cglib.proxy.Enhancer
|
import cn.tursom.proxy.container.ListProxyContainer
|
||||||
import net.sf.cglib.proxy.Factory
|
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
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
object Proxy {
|
object Proxy {
|
||||||
object CallSuperException : Exception()
|
|
||||||
|
|
||||||
val callSuper = object : ThreadLocal<Boolean>() {
|
|
||||||
override fun initialValue(): Boolean = throw CallSuperException
|
|
||||||
override fun get(): Boolean = try {
|
|
||||||
super.get()
|
|
||||||
} catch (_: CallSuperException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultContainer: () -> MutableProxyContainer = { ListProxyContainer() }
|
var defaultContainer: () -> MutableProxyContainer = { ListProxyContainer() }
|
||||||
private val cache = ConcurrentHashMap<Class<*>, Class<*>>()
|
private val cache = ConcurrentHashMap<Class<*>, Class<*>>()
|
||||||
|
val directAccessorKey = ProxyContainer.ctxEnv.newKey<Any>()
|
||||||
|
|
||||||
|
private val methodProxyFieldSignature = MethodProxy::class.java.getDeclaredField("sig1").also {
|
||||||
|
it.isAccessible = true
|
||||||
|
it.final = false
|
||||||
|
}
|
||||||
|
|
||||||
fun getContainer(obj: Any): ProxyContainer? {
|
fun getContainer(obj: Any): ProxyContainer? {
|
||||||
if (obj !is Factory) return null
|
if (obj !is Factory) return null
|
||||||
@ -38,18 +41,88 @@ object Proxy {
|
|||||||
builder: (Class<T>) -> T,
|
builder: (Class<T>) -> T,
|
||||||
): Pair<T, MutableProxyContainer> {
|
): Pair<T, MutableProxyContainer> {
|
||||||
val target = getCachedTarget(clazz)
|
val target = getCachedTarget(clazz)
|
||||||
|
|
||||||
|
val directAccessor = builder(target)
|
||||||
val obj = 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
|
return obj to container
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Any> get() = get(T::class.java)
|
inline fun <reified T : Any> get() = get(T::class.java)
|
||||||
inline fun <reified T : Any> get(
|
inline operator fun <reified T : Any> get(
|
||||||
argumentTypes: Array<out Class<*>>,
|
argumentTypes: Array<out Class<*>>,
|
||||||
arguments: Array<out Any?>,
|
arguments: Array<out Any?>,
|
||||||
container: MutableProxyContainer = defaultContainer(),
|
container: MutableProxyContainer = defaultContainer(),
|
||||||
) = get(T::class.java, argumentTypes, arguments, container)
|
) = get(T::class.java, argumentTypes, arguments, container)
|
||||||
|
|
||||||
|
inline operator fun <reified T : Any, reified A1 : Any?> get(
|
||||||
|
a1: A1,
|
||||||
|
container: MutableProxyContainer = defaultContainer(),
|
||||||
|
) = get<T>(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<T>(
|
||||||
|
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<T>(
|
||||||
|
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<T>(
|
||||||
|
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<T>(
|
||||||
|
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 <T : Any> get(clazz: Class<T>, container: MutableProxyContainer = defaultContainer()) =
|
operator fun <T : Any> get(clazz: Class<T>, container: MutableProxyContainer = defaultContainer()) =
|
||||||
get(clazz, container, Class<T>::newInstance)
|
get(clazz, container, Class<T>::newInstance)
|
||||||
|
|
||||||
@ -68,23 +141,56 @@ object Proxy {
|
|||||||
if (interfaces.isNotEmpty()) {
|
if (interfaces.isNotEmpty()) {
|
||||||
enhancer.setInterfaces(interfaces)
|
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
|
return enhancer
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun injectCallback(obj: Any, container: ProxyContainer = defaultContainer()): ProxyContainer {
|
fun injectCallback(obj: Any, container: ProxyContainer = defaultContainer(), target: Any = obj): ProxyContainer {
|
||||||
obj as Factory
|
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
|
return (obj.getCallback(0) as ProxyInterceptor).container
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.setCallback(0, ProxyInterceptor(container))
|
val nonProxyClasses: MutableSet<Class<*>> = HashSet(listOf(Any::class.java))
|
||||||
|
repeat(obj.callbacks.size) {
|
||||||
|
obj.setCallback(it, LocalCachedProxyInterceptor(container, nonProxyClasses, target))
|
||||||
|
}
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> getCachedTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) {
|
fun <T : Any> getCachedTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) {
|
||||||
newEnhancer(clazz).createClass()
|
newEnhancer(clazz).createClass()
|
||||||
}.uncheckedCast()
|
}.uncheckedCast()
|
||||||
|
|
||||||
|
fun <T : Any> 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package cn.tursom.proxy
|
|
||||||
|
|
||||||
import cn.tursom.core.context.ArrayContextEnv
|
|
||||||
import cn.tursom.core.context.Context
|
|
||||||
|
|
||||||
interface ProxyContainer : Iterable<ProxyMethod> {
|
|
||||||
companion object {
|
|
||||||
val contextEnv = ArrayContextEnv()
|
|
||||||
|
|
||||||
inline fun ProxyContainer.forEachProxy(action: (ProxyMethod) -> Unit) {
|
|
||||||
for (t in this) {
|
|
||||||
action(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <R> ProxyContainer.forFirstProxy(action: (ProxyMethod) -> ProxyResult<R>): ProxyResult<R> {
|
|
||||||
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
|
|
||||||
}
|
|
@ -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<out Any>, proxy: MethodProxy): Any {
|
|
||||||
Proxy.injectCallback(obj)
|
|
||||||
return proxy(obj, args)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<out Any?>, 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<out Any?>) -> ProxyResult<*>
|
|
||||||
|
|
||||||
interface ProxyMethod {
|
|
||||||
@Throws(Throwable::class)
|
|
||||||
fun onProxy(
|
|
||||||
ignored: Any,
|
|
||||||
c: ProxyContainer,
|
|
||||||
method: Method,
|
|
||||||
args: Array<out Any?>,
|
|
||||||
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<Any>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<Any>()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val handlerCacheMapMap: MutableMap<
|
|
||||||
Class<out ProxyMethod>,
|
|
||||||
MutableMap<Method, ProxyResult<ProxyMethodHandler>>
|
|
||||||
> = HashMap()
|
|
||||||
|
|
||||||
fun getHandlerCacheMap(type: Class<out ProxyMethod>): MutableMap<Method, ProxyResult<ProxyMethodHandler>> {
|
|
||||||
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<out Any?>) -> Any? = MethodAccess::invoke
|
|
||||||
|
|
||||||
operator fun get(
|
|
||||||
proxy: ProxyMethod,
|
|
||||||
method: Method,
|
|
||||||
handlerCacheMap: MutableMap<Method, ProxyResult<ProxyMethodHandler>>
|
|
||||||
): 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<out Any?>): ProxyResult<*> {
|
|
||||||
return ProxyResult.of(fastInvoker(methodAccess, proxy, index, args))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class JavaReflectProxyMethodInvoker(
|
|
||||||
val method: Method,
|
|
||||||
) : ProxyMethodHandler {
|
|
||||||
companion object {
|
|
||||||
private val fastInvoker: Method.(Any, Array<out Any?>) -> Any? = Method::invoke
|
|
||||||
|
|
||||||
operator fun get(
|
|
||||||
proxy: ProxyMethod,
|
|
||||||
method: Method,
|
|
||||||
handlerCacheMap: MutableMap<Method, ProxyResult<ProxyMethodHandler>>
|
|
||||||
): 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<out Any?>): ProxyResult<*> {
|
|
||||||
return ProxyResult.of(fastInvoker(method, proxy, args))
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<out Any?>,
|
|
||||||
proxy: MethodProxy
|
|
||||||
) -> ProxyResult<*>
|
|
||||||
|
|
||||||
class ProxyMethodCache(
|
|
||||||
private var lastModify: Long = 0,
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
val failed: ProxyMethodCacheFunction = { _, _, _, _, _ -> ProxyResult.failed }
|
|
||||||
}
|
|
||||||
|
|
||||||
private val functionMap = ConcurrentHashMap<MethodProxy, ProxyMethodCacheFunction>()
|
|
||||||
|
|
||||||
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<out Any?>,
|
|
||||||
proxy: MethodProxy,
|
|
||||||
): ProxyResult<*>? = if (lastModify != this.lastModify) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
functionMap[proxy]?.invoke(obj, c, method, args, proxy)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package cn.tursom.proxy
|
|
||||||
|
|
||||||
import cn.tursom.core.uncheckedCast
|
|
||||||
|
|
||||||
data class ProxyResult<out R>(
|
|
||||||
val result: R,
|
|
||||||
val success: Boolean = false,
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
val success: ProxyResult<*> = ProxyResult<Any?>(null, true)
|
|
||||||
val failed: ProxyResult<*> = ProxyResult<Any?>(null, false)
|
|
||||||
|
|
||||||
fun <R> of(): ProxyResult<R?> = success.uncheckedCast()
|
|
||||||
fun <R> of(result: R): ProxyResult<R> = if (result == null) {
|
|
||||||
success.uncheckedCast()
|
|
||||||
} else {
|
|
||||||
ProxyResult(result, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> failed(): ProxyResult<R> = failed.uncheckedCast()
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<ProxyMethodCache>()
|
|
||||||
.withDefault { ProxyMethodCache() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* will be call when proxy method invoke.
|
|
||||||
* 在代理方法被调用时,该方法会被调用
|
|
||||||
*/
|
|
||||||
@Throws(Throwable::class)
|
|
||||||
fun onProxy(obj: Any, c: ProxyContainer, method: Method, args: Array<out Any?>, 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<out Any?>,
|
|
||||||
proxy: MethodProxy,
|
|
||||||
forFirstProxy: ForFirstProxy,
|
|
||||||
classes: Collection<Class<*>>,
|
|
||||||
): 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<String>(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<ProxyMethod>()
|
|
||||||
private fun onForeachProxy(
|
|
||||||
classes: Collection<Class<*>>,
|
|
||||||
cache: Boolean,
|
|
||||||
): ProxyMethodCacheFunction = { o, c, m, a, proxy ->
|
|
||||||
val proxyList = if (cache) ArrayList<ProxyMethod>() 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<Any?>()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onCachedForeachProxy(proxyList: List<ProxyMethod>): ProxyMethodCacheFunction = { o, c, m, a, proxy ->
|
|
||||||
proxyList.forEach { p ->
|
|
||||||
p.onProxy(o, c, m, a, proxy)
|
|
||||||
}
|
|
||||||
ProxyResult.failed<Any?>()
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,7 @@ annotation class ForFirstProxy(
|
|||||||
*/
|
*/
|
||||||
val must: Boolean = false,
|
val must: Boolean = false,
|
||||||
val errMsg: String = "",
|
val errMsg: String = "",
|
||||||
val errClass: KClass<out RuntimeException> = RuntimeException::class,
|
val errClass: KClass<out Throwable> = Throwable::class,
|
||||||
val cache: Boolean = true,
|
val cache: Boolean = true,
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -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<Any> = 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<Any>?) {
|
||||||
|
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<Any> {
|
||||||
|
return proxyList.iterator()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package cn.tursom.proxy.container
|
||||||
|
|
||||||
|
interface MutableProxyContainer : ProxyContainer {
|
||||||
|
override var target: Any
|
||||||
|
|
||||||
|
fun addProxy(proxy: Any)
|
||||||
|
fun addAllProxy(proxy: Collection<Any>?)
|
||||||
|
fun removeProxy(proxy: Any)
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package cn.tursom.proxy.container
|
||||||
|
|
||||||
|
import cn.tursom.core.context.ArrayContextEnv
|
||||||
|
import cn.tursom.core.context.Context
|
||||||
|
|
||||||
|
interface ProxyContainer : Iterable<Any> {
|
||||||
|
companion object {
|
||||||
|
val ctxEnv = ArrayContextEnv()
|
||||||
|
}
|
||||||
|
|
||||||
|
// to impl, use override val context: Context = ProxyContainer.contextEnv.newContext()
|
||||||
|
val ctx: Context
|
||||||
|
val target: Any
|
||||||
|
}
|
@ -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<ProxyMethodCache>()
|
||||||
|
.withDefault { ProxyMethodCache() }
|
||||||
|
}
|
||||||
|
|
||||||
|
//private val functionMap = HashMap<Int, ProxyMethodCacheFunction>()
|
||||||
|
private val functionMap = IntMap<ProxyMethodCacheFunction>()
|
||||||
|
|
||||||
|
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]
|
||||||
|
}
|
@ -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<out Any?>?,
|
||||||
|
MethodProxy?,
|
||||||
|
) -> Any?
|
@ -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>,
|
||||||
|
) : ProxyMethodCacheFunction {
|
||||||
|
override fun invoke(
|
||||||
|
o: Any?,
|
||||||
|
c: ProxyContainer,
|
||||||
|
m: Method?,
|
||||||
|
a: Array<out Any?>?,
|
||||||
|
proxy: MethodProxy?,
|
||||||
|
): Any? {
|
||||||
|
proxy!!
|
||||||
|
|
||||||
|
proxyList.forEach { p ->
|
||||||
|
p(o, c, m, a, proxy)
|
||||||
|
}
|
||||||
|
return proxy.invokeSuper(o, a)
|
||||||
|
}
|
||||||
|
}
|
@ -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<out Any?>?,
|
||||||
|
proxy: MethodProxy?,
|
||||||
|
): Any? {
|
||||||
|
return proxy!!.invokeSuper(obj, args)
|
||||||
|
}
|
||||||
|
}
|
@ -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<out Any?>?) -> 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<out Any?>?,
|
||||||
|
proxy: MethodProxy?,
|
||||||
|
): Any? {
|
||||||
|
return fastInvoker(this.method, self, args)
|
||||||
|
}
|
||||||
|
}
|
@ -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<ProxyMethodCacheFunction>()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val classes: Collection<Class<*>> = 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<out Any?>?,
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -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<Class<*>> = 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<out Any?>?,
|
||||||
|
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<String>(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<out Throwable>,
|
||||||
|
private val errMsg: String,
|
||||||
|
) : ProxyMethodCacheFunction {
|
||||||
|
override fun invoke(
|
||||||
|
obj: Any?,
|
||||||
|
c: ProxyContainer,
|
||||||
|
method: Method?,
|
||||||
|
args: Array<out Any?>?,
|
||||||
|
proxy: MethodProxy?,
|
||||||
|
) = throw exceptionConstructor.newInstance(errMsg)
|
||||||
|
}
|
@ -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<out Any?>?,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<out Any?>?,
|
||||||
|
proxy: MethodProxy?,
|
||||||
|
): Any? {
|
||||||
|
return proxyMethod.onProxyInvoke(obj, c, method, args, proxy, next)
|
||||||
|
}
|
||||||
|
}
|
@ -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<out Any?>?) -> 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<out Any?>?,
|
||||||
|
proxy: MethodProxy?,
|
||||||
|
): Any? {
|
||||||
|
return fastInvoker(methodAccess, self, index, args)
|
||||||
|
}
|
||||||
|
}
|
@ -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<out Any?>?) -> Any? = MethodAccess::invoke
|
||||||
|
}
|
||||||
|
|
||||||
|
private var handler: (method: Method?, args: Array<out Any>?) -> Any? = DefaultHandler()
|
||||||
|
|
||||||
|
override fun invoke(ignore: Any, method: Method?, args: Array<out Any>?): Any? {
|
||||||
|
return handler(method, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class DefaultHandler : (Method?, Array<out Any>?) -> Any? {
|
||||||
|
override fun invoke(method: Method?, args: Array<out Any>?): 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<out Any>?) -> Any? {
|
||||||
|
override fun invoke(method: Method?, args: Array<out Any>?) = fastInvoker(methodAccess, proxy, index, args)
|
||||||
|
}
|
||||||
|
}
|
@ -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<Class<*>>,
|
||||||
|
val target: Any,
|
||||||
|
) : ProxyInterceptor(container, nonProxyClasses) {
|
||||||
|
private var cache: ProxyMethodCacheFunction? = null
|
||||||
|
|
||||||
|
override fun intercept(obj: Any?, method: Method?, args: Array<out Any?>?, 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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<out Any>?, proxy: MethodProxy): Any? {
|
||||||
|
return proxy.invokeSuper(target, args)
|
||||||
|
}
|
||||||
|
}
|
@ -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<Class<*>> = HashSet(listOf(Any::class.java)),
|
||||||
|
) : MethodInterceptor {
|
||||||
|
override fun intercept(obj: Any?, method: Method?, args: Array<out Any?>?, 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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 cn.tursom.reflect.asm.ReflectAsmUtils
|
||||||
import net.sf.cglib.core.Signature
|
import net.sf.cglib.core.Signature
|
||||||
import net.sf.cglib.proxy.Callback
|
import net.sf.cglib.proxy.Callback
|
||||||
import net.sf.cglib.proxy.MethodProxy
|
import net.sf.cglib.proxy.MethodProxy
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
object CglibUtil {
|
object CglibUtil {
|
||||||
fun getFactoryData(clazz: Class<*>): Any? {
|
fun getFactoryData(clazz: Class<*>): Any? {
|
||||||
@ -37,4 +40,4 @@ object CglibUtil {
|
|||||||
"CGLIB\$SET_STATIC_CALLBACKS"
|
"CGLIB\$SET_STATIC_CALLBACKS"
|
||||||
)!!(callbacks)
|
)!!(callbacks)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package cn.tursom.proxy.util
|
||||||
|
|
||||||
|
import cn.tursom.core.uncheckedCast
|
||||||
|
|
||||||
|
class IntMap<V> {
|
||||||
|
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<Any>(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
|
||||||
|
}
|
||||||
|
}
|
@ -1,57 +1,86 @@
|
|||||||
package cn.tursom.proxy
|
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.junit.Test
|
||||||
import org.objectweb.asm.ClassWriter
|
import org.objectweb.asm.ClassWriter
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class Example {
|
class Example {
|
||||||
|
companion object{
|
||||||
|
var bytes: ByteArray? = null
|
||||||
|
|
||||||
|
fun saveBytes(b: ByteArray) {
|
||||||
|
bytes = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open class TestClass protected constructor() {
|
open class TestClass protected constructor() {
|
||||||
//@get:ForEachProxy
|
|
||||||
open var a: Int = 0
|
open var a: Int = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetA(
|
class GetA(
|
||||||
private val t: TestClass,
|
t: TestClass,
|
||||||
) : ProxyMethod {
|
) {
|
||||||
fun getA(): Int {
|
val t: TestClass = Proxy.getSuperCaller(t)
|
||||||
Proxy.callSuper.set(true)
|
|
||||||
return t.a + 1
|
val a: Int
|
||||||
}
|
get() = t.a + 1
|
||||||
|
|
||||||
|
//fun getA(): Int {
|
||||||
|
// return t.a + 1
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getClass() {
|
fun getClass() {
|
||||||
|
val access = MethodAccess.get(TestClass::class.java)
|
||||||
|
println(access)
|
||||||
|
|
||||||
val writer = ClassWriter(0)
|
val writer = ClassWriter(0)
|
||||||
val enhancer = Proxy.newEnhancer(TestClass::class.java)
|
val enhancer = Proxy.newEnhancer(TestClass::class.java)
|
||||||
|
|
||||||
|
enhancer.setCallbackType(InvocationHandler::class.java)
|
||||||
|
enhancer.setCallbackFilter { 0 }
|
||||||
|
|
||||||
val clazz = enhancer.createClass()
|
val clazz = enhancer.createClass()
|
||||||
CglibUtil.setStaticCallbacks(clazz, arrayOf(ProxyInterceptor()))
|
//CglibUtil.setStaticCallbacks(clazz, arrayOf(ProxyInterceptor()))
|
||||||
val instance = clazz.newInstance()
|
//val instance = clazz.newInstance()
|
||||||
enhancer.generateClass(writer)
|
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<TestClass>()
|
||||||
|
|
||||||
|
MethodAccess.get(t.javaClass)!!
|
||||||
|
//File("TestClass_MethodAccess.class").writeBytes(bytes!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun 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<TestClass>()
|
val (t, container) = Proxy.get<TestClass>()
|
||||||
//val t = Proxy.getCachedTarget(TestClass::class.java).newInstance()
|
val getA = GetA(t)
|
||||||
//val container = Proxy.injectCallback(t)
|
println(getA.t == t)
|
||||||
//container as MutableProxyContainer
|
|
||||||
container.addProxy(GetA(t))
|
container.addProxy(getA)
|
||||||
|
|
||||||
println(t.javaClass)
|
println(t.javaClass)
|
||||||
repeat(10) {
|
repeat(10) {
|
||||||
|
Loading…
Reference in New Issue
Block a user