fix bugs and reconstruct

This commit is contained in:
tursom 2023-01-18 20:28:43 +08:00
parent 225adfa9fc
commit acf16136a4
6 changed files with 147 additions and 69 deletions

View File

@ -29,4 +29,4 @@ class ListProxyContainer(
lastModify = System.currentTimeMillis()
return proxyList.iterator()
}
}
}

View File

@ -27,33 +27,33 @@ object Proxy {
}
fun addProxy(obj: Any, proxy: ProxyMethod): Boolean {
val container = getContainer(obj) ?: return false
(container as? MutableProxyContainer)?.addProxy(proxy) ?: return false
val container = getContainer(obj) as? MutableProxyContainer ?: return false
container.addProxy(proxy)
return true
}
inline operator fun <T> get(
inline operator fun <T : Any> get(
clazz: Class<T>,
container: MutableProxyContainer = defaultContainer(),
builder: (Class<T>) -> T,
): Pair<T, MutableProxyContainer> {
val target = getCachedTarget(clazz)
val obj = builder(target)
injectCallback(obj as Factory) { container }
injectCallback(obj as Factory, container)
return obj to container
}
inline fun <reified T> get() = get(T::class.java)
inline fun <reified T> get(
inline fun <reified T : Any> get() = get(T::class.java)
inline fun <reified T : Any> get(
argumentTypes: Array<out Class<*>>,
arguments: Array<out Any?>,
container: MutableProxyContainer = defaultContainer(),
) = get(T::class.java, argumentTypes, arguments, container)
operator fun <T> get(clazz: Class<T>, container: MutableProxyContainer = defaultContainer()) =
operator fun <T : Any> get(clazz: Class<T>, container: MutableProxyContainer = defaultContainer()) =
get(clazz, container, Class<T>::newInstance)
operator fun <T> get(
operator fun <T : Any> get(
clazz: Class<T>,
argumentTypes: Array<out Class<*>>,
arguments: Array<out Any?>,
@ -62,7 +62,7 @@ object Proxy {
it.getConstructor(*argumentTypes).newInstance(*arguments)
}
fun <T> newEnhancer(clazz: Class<T>, vararg interfaces: Class<*>): Enhancer {
fun <T : Any> newEnhancer(clazz: Class<T>, vararg interfaces: Class<*>): Enhancer {
val enhancer = Enhancer()
enhancer.setSuperclass(clazz)
if (interfaces.isNotEmpty()) {
@ -74,15 +74,17 @@ object Proxy {
}
@JvmOverloads
inline fun injectCallback(obj: Any, container: () -> ProxyContainer = { defaultContainer() }): ProxyContainer {
fun injectCallback(obj: Any, container: ProxyContainer = defaultContainer()): ProxyContainer {
obj as Factory
if (obj.getCallback(0) == null || obj.getCallback(0) == ProxyDispatcher) {
obj.setCallback(0, ProxyInterceptor(container()))
if (obj.getCallback(0) != null && obj.getCallback(0) != ProxyDispatcher) {
return (obj.getCallback(0) as ProxyInterceptor).container
}
return (obj.getCallback(0) as ProxyInterceptor).container
obj.setCallback(0, ProxyInterceptor(container))
return container
}
fun <T> getCachedTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) {
fun <T : Any> getCachedTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) {
newEnhancer(clazz).createClass()
}.uncheckedCast()
}

View File

@ -3,65 +3,40 @@ 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(obj: Any, c: ProxyContainer, method: Method, args: Array<out Any?>, proxy: MethodProxy): ProxyResult<*> {
fun onProxy(
ignored: Any,
c: ProxyContainer,
method: Method,
args: Array<out Any?>,
proxy: MethodProxy
): ProxyResult<*> {
val handlerCacheMap = getHandlerCacheMap(javaClass)
val methodResult = handlerCacheMap[method]
if (methodResult != null) {
return if (methodResult.success) {
methodResult.result(this, args)
val handlerCache = handlerCacheMap[method]
if (handlerCache != null) {
return if (handlerCache.success) {
handlerCache.result(this, args)
} else {
ProxyResult.failed<Any>()
}
}
val reflectAsmMethod = try {
ReflectAsmUtils.getMethod(
javaClass,
method.name,
paramTypes = method.parameterTypes,
returnType = method.returnType,
)
} catch (e: Exception) {
e.printStackTrace()
null
}
if (reflectAsmMethod != null) {
val (methodAccess, index) = reflectAsmMethod
handlerCacheMap[method] = ProxyResult({ p, a ->
ProxyResult.of(methodAccess.invoke(p, index, *a))
}, true)
return ProxyResult.of(methodAccess.invoke(this, index, *args))
val reflectAsmHandler = ReflectASMProxyMethodInvoker[this, method, handlerCacheMap]
if (reflectAsmHandler != null) {
return reflectAsmHandler(this, args)
}
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 = javaClass.getMethod(methodName, *method.parameterTypes)
selfMethod.isAccessible = true
handlerCacheMap[method] = ProxyResult({ p, a ->
ProxyResult.of(selfMethod(p, *a))
}, true)
return ProxyResult.of<Any>(selfMethod(this, *args))
} catch (_: Exception) {
val javaReflectHandler = JavaReflectProxyMethodInvoker[this, method, handlerCacheMap]
if (javaReflectHandler != null) {
javaReflectHandler(this, args)
}
handlerCacheMap[method] = ProxyResult.failed()
@ -71,10 +46,10 @@ interface ProxyMethod {
companion object {
private val handlerCacheMapMap: MutableMap<
Class<out ProxyMethod>,
MutableMap<Method, ProxyResult<(proxy: ProxyMethod, args: Array<out Any?>) -> ProxyResult<*>>>> =
HashMap()
MutableMap<Method, ProxyResult<ProxyMethodHandler>>
> = HashMap()
fun getHandlerCacheMap(type: Class<out ProxyMethod>): MutableMap<Method, ProxyResult<(proxy: ProxyMethod, args: Array<out Any?>) -> ProxyResult<*>>> {
fun getHandlerCacheMap(type: Class<out ProxyMethod>): MutableMap<Method, ProxyResult<ProxyMethodHandler>> {
var handlerCacheMap = handlerCacheMapMap[type]
if (handlerCacheMap == null) synchronized(handlerCacheMapMap) {
handlerCacheMap = handlerCacheMapMap[type]
@ -86,4 +61,90 @@ interface ProxyMethod {
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))
}
}

View File

@ -4,7 +4,13 @@ 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<*>
typealias ProxyMethodCacheFunction = (
obj: Any,
c: ProxyContainer,
method: Method,
args: Array<out Any?>,
proxy: MethodProxy
) -> ProxyResult<*>
class ProxyMethodCache(
private var lastModify: Long = 0,
@ -16,6 +22,10 @@ class ProxyMethodCache(
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
}
@ -30,6 +40,6 @@ class ProxyMethodCache(
): ProxyResult<*>? = if (lastModify != this.lastModify) {
null
} else {
(functionMap[proxy] ?: failed)(obj, c, method, args, proxy)
functionMap[proxy]?.invoke(obj, c, method, args, proxy)
}
}

View File

@ -5,13 +5,18 @@ import cn.tursom.core.uncheckedCast
data class ProxyResult<out R>(
val result: R,
val success: Boolean = false,
val cache: Boolean = true,
) {
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> = ProxyResult(result, true)
fun <R> of(result: R): ProxyResult<R> = if (result == null) {
success.uncheckedCast()
} else {
ProxyResult(result, true)
}
fun <R> failed(): ProxyResult<R> = failed.uncheckedCast()
}
}

View File

@ -67,7 +67,7 @@ object ProxyRunner {
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 && result.cache) {
if (forFirstProxy.cache && result.success) {
container.context[proxyMethodCacheKey].update(container.lastModify, proxy, p::onProxy)
}
return@forFirstProxy result