mirror of
https://github.com/tursom/TursomServer.git
synced 2024-12-26 12:50:24 +08:00
make Proxy run faster
This commit is contained in:
parent
68648b1f77
commit
56375ce172
@ -0,0 +1,40 @@
|
||||
package cn.tursom.proxy
|
||||
|
||||
import cn.tursom.reflect.asm.ReflectAsmUtils
|
||||
import net.sf.cglib.core.Signature
|
||||
import net.sf.cglib.proxy.Callback
|
||||
import net.sf.cglib.proxy.MethodProxy
|
||||
|
||||
object CglibUtil {
|
||||
fun getFactoryData(clazz: Class<*>): Any? {
|
||||
val (fieldAccess, i) = ReflectAsmUtils.getField(clazz, "CGLIB\$FACTORY_DATA")!!
|
||||
return fieldAccess.get(null, i)
|
||||
}
|
||||
|
||||
fun getCallbackFilter(clazz: Class<*>): Any? {
|
||||
val field = clazz.getDeclaredField("CGLIB\$CALLBACK_FILTER")
|
||||
field.isAccessible = true
|
||||
return field.get(null)
|
||||
}
|
||||
|
||||
fun findMethodProxy(clazz: Class<*>, signature: Signature): MethodProxy? {
|
||||
return ReflectAsmUtils.getStaticMethod1<Signature, MethodProxy?>(
|
||||
clazz,
|
||||
"CGLIB\$findMethodProxy"
|
||||
)!!(signature)
|
||||
}
|
||||
|
||||
fun setThreadCallbacks(clazz: Class<*>, callbacks: Array<out Callback>) {
|
||||
ReflectAsmUtils.getStaticMethod1<Array<out Callback>, Unit?>(
|
||||
clazz,
|
||||
"CGLIB\$SET_THREAD_CALLBACKS"
|
||||
)!!(callbacks)
|
||||
}
|
||||
|
||||
fun setStaticCallbacks(clazz: Class<*>, callbacks: Array<out Callback>) {
|
||||
ReflectAsmUtils.getStaticMethod1<Array<out Callback>, Unit?>(
|
||||
clazz,
|
||||
"CGLIB\$SET_STATIC_CALLBACKS"
|
||||
)!!(callbacks)
|
||||
}
|
||||
}
|
@ -6,27 +6,40 @@ import net.sf.cglib.proxy.Factory
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object Proxy {
|
||||
val enhancerMap = ConcurrentHashMap<Class<*>, Enhancer>()
|
||||
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() }
|
||||
private val cache = ConcurrentHashMap<Class<*>, Class<*>>()
|
||||
|
||||
private fun <T> getTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) {
|
||||
val enhancer = Enhancer()
|
||||
enhancerMap[clazz] = enhancer
|
||||
enhancer.setSuperclass(clazz)
|
||||
enhancer.setCallbackType(ProxyInterceptor::class.java)
|
||||
enhancer.setCallbackFilter { 0 }
|
||||
enhancer.createClass()
|
||||
}.uncheckedCast()
|
||||
fun getContainer(obj: Any): ProxyContainer? {
|
||||
if (obj !is Factory) return null
|
||||
val interceptor = obj.getCallback(0) as? ProxyInterceptor ?: return null
|
||||
return interceptor.container
|
||||
}
|
||||
|
||||
operator fun <T> get(
|
||||
fun addProxy(obj: Any, proxy: ProxyMethod): Boolean {
|
||||
val container = getContainer(obj) ?: return false
|
||||
(container as? MutableProxyContainer)?.addProxy(proxy) ?: return false
|
||||
return true
|
||||
}
|
||||
|
||||
inline operator fun <T> get(
|
||||
clazz: Class<T>,
|
||||
container: MutableProxyContainer = defaultContainer(),
|
||||
builder: (Class<T>) -> T,
|
||||
): Pair<T, MutableProxyContainer> {
|
||||
val target = getTarget(clazz)
|
||||
val container = ListProxyContainer()
|
||||
val target = getCachedTarget(clazz)
|
||||
val obj = builder(target)
|
||||
obj as Factory
|
||||
obj.setCallback(0, ProxyInterceptor(container))
|
||||
injectCallback(obj as Factory) { container }
|
||||
return obj to container
|
||||
}
|
||||
|
||||
@ -34,15 +47,42 @@ object Proxy {
|
||||
inline fun <reified T> get(
|
||||
argumentTypes: Array<out Class<*>>,
|
||||
arguments: Array<out Any?>,
|
||||
) = get(T::class.java, argumentTypes, arguments)
|
||||
container: MutableProxyContainer = defaultContainer(),
|
||||
) = get(T::class.java, argumentTypes, arguments, container)
|
||||
|
||||
operator fun <T> get(clazz: Class<T>) = get(clazz, Class<T>::newInstance)
|
||||
operator fun <T> get(clazz: Class<T>, container: MutableProxyContainer = defaultContainer()) =
|
||||
get(clazz, container, Class<T>::newInstance)
|
||||
|
||||
operator fun <T> get(
|
||||
clazz: Class<T>,
|
||||
argumentTypes: Array<out Class<*>>,
|
||||
arguments: Array<out Any?>,
|
||||
) = get(clazz) {
|
||||
container: MutableProxyContainer = defaultContainer(),
|
||||
) = get(clazz, container) {
|
||||
it.getConstructor(*argumentTypes).newInstance(*arguments)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> newEnhancer(clazz: Class<T>, vararg interfaces: Class<*>): Enhancer {
|
||||
val enhancer = Enhancer()
|
||||
enhancer.setSuperclass(clazz)
|
||||
if (interfaces.isNotEmpty()) {
|
||||
enhancer.setInterfaces(interfaces)
|
||||
}
|
||||
enhancer.setCallbackType(ProxyInterceptor::class.java)
|
||||
enhancer.setCallbackFilter { 0 }
|
||||
return enhancer
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
inline 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()))
|
||||
}
|
||||
return (obj.getCallback(0) as ProxyInterceptor).container
|
||||
}
|
||||
|
||||
fun <T> getCachedTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) {
|
||||
newEnhancer(clazz).createClass()
|
||||
}.uncheckedCast()
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
package cn.tursom.proxy
|
||||
|
||||
import net.sf.cglib.proxy.MethodProxy
|
||||
import java.lang.reflect.Method
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object ProxyContainerHandlerCache {
|
||||
private val handlerMap: MutableMap<MethodProxy, (Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<Any?>> =
|
||||
ConcurrentHashMap()
|
||||
val callSuper = { obj: Any, _: ProxyContainer, _: Method, args: Array<out Any?>, proxy: MethodProxy ->
|
||||
ProxyResult.of<Any?>(proxy.invokeSuper(obj, args))
|
||||
}
|
||||
val empty = { _: Any, _: ProxyContainer, _: Method, _: Array<out Any?>, _: MethodProxy -> ProxyResult.failed<Any?>() }
|
||||
|
||||
fun getHandler(method: MethodProxy): ((Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<Any?>)? {
|
||||
return handlerMap[method]
|
||||
}
|
||||
|
||||
fun setHandler(
|
||||
method: MethodProxy,
|
||||
onProxy: ((Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<Any?>)?,
|
||||
) {
|
||||
handlerMap[method] = onProxy ?: callSuper
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
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)
|
||||
}
|
||||
}
|
@ -2,39 +2,16 @@ package cn.tursom.proxy
|
||||
|
||||
import net.sf.cglib.proxy.MethodInterceptor
|
||||
import net.sf.cglib.proxy.MethodProxy
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import java.util.*
|
||||
|
||||
class ProxyInterceptor(
|
||||
private val container: ProxyContainer = ListProxyContainer(),
|
||||
val container: ProxyContainer = ListProxyContainer(),
|
||||
// disable call super can save 20% time
|
||||
private val supportCallSuper: Boolean = true,
|
||||
) : MethodInterceptor {
|
||||
companion object {
|
||||
val callSuper = ThreadLocal<Boolean?>()
|
||||
private val parameterTypes = arrayOf(Method::class.java, Array<Any>::class.java, MethodProxy::class.java)
|
||||
private val parameterTypesField: Field = Method::class.java.getDeclaredField("parameterTypes").apply {
|
||||
isAccessible = true
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun getParameterTypes(method: Method): Array<Class<*>> {
|
||||
return parameterTypesField[method] as Array<Class<*>>
|
||||
}
|
||||
|
||||
fun equalsMethod(method: Method, name: String?, parameterTypes: Array<Class<*>>?): Boolean {
|
||||
return method.name == name && parameterTypes.contentEquals(getParameterTypes(method))
|
||||
}
|
||||
|
||||
fun isOnProxyMethod(method: Method): Boolean {
|
||||
//return callSuper.get() == true || equalsMethod(method, "onProxy", parameterTypes)
|
||||
return callSuper.get() == true
|
||||
}
|
||||
}
|
||||
|
||||
override fun intercept(obj: Any, method: Method, args: Array<out Any?>, proxy: MethodProxy): Any? {
|
||||
if (supportCallSuper && callSuper.get() == true) {
|
||||
callSuper.remove()
|
||||
if (supportCallSuper && Proxy.callSuper.get()) {
|
||||
Proxy.callSuper.remove()
|
||||
return proxy.invokeSuper(obj, args)
|
||||
}
|
||||
|
||||
@ -45,4 +22,4 @@ class ProxyInterceptor(
|
||||
proxy.invokeSuper(obj, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,12 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
interface ProxyMethod {
|
||||
@Throws(Throwable::class)
|
||||
fun onProxy(obj: Any?, method: Method, args: Array<out Any?>, proxy: MethodProxy): ProxyResult<*> {
|
||||
fun onProxy(obj: 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) {
|
||||
ProxyResult.of(methodResult.result(this, args))
|
||||
methodResult.result(this, args)
|
||||
} else {
|
||||
ProxyResult.failed<Any>()
|
||||
}
|
||||
@ -34,7 +34,7 @@ interface ProxyMethod {
|
||||
if (reflectAsmMethod != null) {
|
||||
val (methodAccess, index) = reflectAsmMethod
|
||||
handlerCacheMap[method] = ProxyResult({ p, a ->
|
||||
methodAccess.invoke(p, index, *a)
|
||||
ProxyResult.of(methodAccess.invoke(p, index, *a))
|
||||
}, true)
|
||||
return ProxyResult.of(methodAccess.invoke(this, index, *args))
|
||||
}
|
||||
@ -58,7 +58,7 @@ interface ProxyMethod {
|
||||
selfMethod = javaClass.getMethod(methodName, *method.parameterTypes)
|
||||
selfMethod.isAccessible = true
|
||||
handlerCacheMap[method] = ProxyResult({ p, a ->
|
||||
selfMethod(p, *a)
|
||||
ProxyResult.of(selfMethod(p, *a))
|
||||
}, true)
|
||||
return ProxyResult.of<Any>(selfMethod(this, *args))
|
||||
} catch (_: Exception) {
|
||||
@ -70,11 +70,11 @@ interface ProxyMethod {
|
||||
|
||||
companion object {
|
||||
private val handlerCacheMapMap: MutableMap<
|
||||
Class<out ProxyMethod>,
|
||||
MutableMap<Method, ProxyResult<(proxy: ProxyMethod, args: Array<out Any?>) -> Any?>>> =
|
||||
Class<out ProxyMethod>,
|
||||
MutableMap<Method, ProxyResult<(proxy: ProxyMethod, args: Array<out Any?>) -> ProxyResult<*>>>> =
|
||||
HashMap()
|
||||
|
||||
fun getHandlerCacheMap(type: Class<out ProxyMethod>): MutableMap<Method, ProxyResult<(proxy: ProxyMethod, args: Array<out Any?>) -> Any?>> {
|
||||
fun getHandlerCacheMap(type: Class<out ProxyMethod>): MutableMap<Method, ProxyResult<(proxy: ProxyMethod, args: Array<out Any?>) -> ProxyResult<*>>> {
|
||||
var handlerCacheMap = handlerCacheMapMap[type]
|
||||
if (handlerCacheMap == null) synchronized(handlerCacheMapMap) {
|
||||
handlerCacheMap = handlerCacheMapMap[type]
|
||||
|
@ -2,31 +2,34 @@ package cn.tursom.proxy
|
||||
|
||||
import net.sf.cglib.proxy.MethodProxy
|
||||
import java.lang.reflect.Method
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
typealias ProxyMethodCacheFunction = (obj: Any?, 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,
|
||||
private var function: ProxyMethodCacheFunction = failed,
|
||||
) {
|
||||
companion object {
|
||||
val failed: ProxyMethodCacheFunction = { _, _, _, _ -> ProxyResult.failed }
|
||||
val failed: ProxyMethodCacheFunction = { _, _, _, _, _ -> ProxyResult.failed }
|
||||
}
|
||||
|
||||
fun update(lastModify: Long, function: ProxyMethodCacheFunction = this.function) {
|
||||
private val functionMap = ConcurrentHashMap<MethodProxy, ProxyMethodCacheFunction>()
|
||||
|
||||
fun update(lastModify: Long, proxy: MethodProxy, function: ProxyMethodCacheFunction = functionMap[proxy] ?: failed) {
|
||||
this.lastModify = lastModify
|
||||
this.function = function
|
||||
functionMap[proxy] = function
|
||||
}
|
||||
|
||||
operator fun invoke(
|
||||
lastModify: Long,
|
||||
obj: Any?,
|
||||
obj: Any,
|
||||
c: ProxyContainer,
|
||||
method: Method,
|
||||
args: Array<out Any?>,
|
||||
proxy: MethodProxy,
|
||||
): ProxyResult<*>? = if (lastModify != this.lastModify) {
|
||||
null
|
||||
} else {
|
||||
function(obj, method, args, proxy)
|
||||
(functionMap[proxy] ?: failed)(obj, c, method, args, proxy)
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import cn.tursom.core.uncheckedCast
|
||||
data class ProxyResult<out R>(
|
||||
val result: R,
|
||||
val success: Boolean = false,
|
||||
val cache: Boolean = false,
|
||||
val cache: Boolean = true,
|
||||
) {
|
||||
companion object {
|
||||
val success: ProxyResult<*> = ProxyResult<Any?>(null, true)
|
||||
|
@ -12,10 +12,8 @@ import java.util.*
|
||||
|
||||
object ProxyRunner {
|
||||
private val errMsgSearchList = arrayOf("%M", "%B", "%A")
|
||||
private val forFirstProxyCacheKey =
|
||||
ProxyContainer.contextEnv.newKey<ProxyMethodCache>().withDefault { ProxyMethodCache() }
|
||||
private val forEachProxyCacheKey =
|
||||
ProxyContainer.contextEnv.newKey<ProxyMethodCache>().withDefault { ProxyMethodCache() }
|
||||
private val proxyMethodCacheKey = ProxyContainer.contextEnv.newKey<ProxyMethodCache>()
|
||||
.withDefault { ProxyMethodCache() }
|
||||
|
||||
/**
|
||||
* will be call when proxy method invoke.
|
||||
@ -23,10 +21,12 @@ object ProxyRunner {
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
fun onProxy(obj: Any, c: ProxyContainer, method: Method, args: Array<out Any?>, proxy: MethodProxy): ProxyResult<*> {
|
||||
var handler = ProxyContainerHandlerCache.getHandler(proxy)
|
||||
if (handler != null) {
|
||||
return handler(obj, c, method, args, proxy)
|
||||
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)
|
||||
@ -41,18 +41,17 @@ object ProxyRunner {
|
||||
//handler = ProxyContainerHandlerCache.callSuper
|
||||
handler = onForFirstProxy(ForFirstProxy.EMPTY)
|
||||
}
|
||||
ProxyContainerHandlerCache.setHandler(proxy, handler)
|
||||
return handler(obj, c, method, args, proxy)
|
||||
}
|
||||
|
||||
private fun onForFirstProxy(forFirstProxy: ForFirstProxy): (Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<*> {
|
||||
return { o: Any, c: ProxyContainer, m: Method, a: Array<out Any?>, p: MethodProxy ->
|
||||
c.context[forFirstProxyCacheKey](c.lastModify, o, m, a, p) ?: onForFirstProxy(o, c, m, a, p, forFirstProxy,
|
||||
when (forFirstProxy.value.size) {
|
||||
0 -> emptyList()
|
||||
1 -> listOf(forFirstProxy.value[0].java)
|
||||
else -> forFirstProxy.value.asSequence().map { it.java }.toSet()
|
||||
})
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,12 +64,11 @@ object ProxyRunner {
|
||||
forFirstProxy: ForFirstProxy,
|
||||
classes: Collection<Class<*>>,
|
||||
): ProxyResult<*> {
|
||||
val cache = container.context[forFirstProxyCacheKey]
|
||||
val result = container.forFirstProxy { p ->
|
||||
if (classes.isEmpty() || classes.stream().anyMatch { c: Class<*> -> c.isInstance(p) }) {
|
||||
val result = p.onProxy(obj, method, args, proxy)
|
||||
val result = p.onProxy(obj, container, method, args, proxy)
|
||||
if (forFirstProxy.cache && result.success && result.cache) {
|
||||
cache.update(container.lastModify, p::onProxy)
|
||||
container.context[proxyMethodCacheKey].update(container.lastModify, proxy, p::onProxy)
|
||||
}
|
||||
return@forFirstProxy result
|
||||
} else {
|
||||
@ -103,34 +101,48 @@ object ProxyRunner {
|
||||
errMsg = StringUtils.replaceEach(errMsg, errMsgSearchList, replacementList)
|
||||
val exceptionConstructor = forFirstProxy.errClass.java.getConstructor(String::class.java)
|
||||
if (forFirstProxy.cache) {
|
||||
cache.update(container.lastModify) { _, _, _, _ ->
|
||||
container.context[proxyMethodCacheKey].update(container.lastModify, proxy) { _, _, _, _, _ ->
|
||||
throw exceptionConstructor.newInstance(errMsg)
|
||||
}
|
||||
}
|
||||
throw exceptionConstructor.newInstance(errMsg)
|
||||
}
|
||||
if (forFirstProxy.cache) {
|
||||
cache.update(container.lastModify)
|
||||
container.context[proxyMethodCacheKey].update(container.lastModify, proxy)
|
||||
}
|
||||
return ProxyResult.failed
|
||||
}
|
||||
|
||||
private fun onForeachProxy(forEachProxy: ForEachProxy) = onForeachProxy(when (forEachProxy.value.size) {
|
||||
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<*>>,
|
||||
): (Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<Any?> {
|
||||
return (label@{ o: Any, c: ProxyContainer, m: Method, a: Array<out Any?>, proxy1: MethodProxy ->
|
||||
c.forEachProxy { p ->
|
||||
if (classes.isEmpty() || classes.any { c: Class<*> -> c.isInstance(p) }) {
|
||||
p.onProxy(o, m, a, proxy1)
|
||||
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)
|
||||
}
|
||||
}
|
||||
ProxyResult.failed<Any?>()
|
||||
})
|
||||
}
|
||||
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?>()
|
||||
}
|
||||
}
|
||||
|
@ -4,4 +4,8 @@ import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ForEachProxy(vararg val value: KClass<*> = [], val name: String = "")
|
||||
annotation class ForEachProxy(
|
||||
vararg val value: KClass<*> = [],
|
||||
val name: String = "",
|
||||
val cache: Boolean = true,
|
||||
)
|
@ -1,6 +1,8 @@
|
||||
package cn.tursom.proxy
|
||||
|
||||
import org.junit.Test
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import java.io.File
|
||||
|
||||
class Example {
|
||||
open class TestClass protected constructor() {
|
||||
@ -12,14 +14,54 @@ class Example {
|
||||
private val t: TestClass,
|
||||
) : ProxyMethod {
|
||||
fun getA(): Int {
|
||||
ProxyInterceptor.callSuper.set(true)
|
||||
Proxy.callSuper.set(true)
|
||||
return t.a + 1
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getClass() {
|
||||
val writer = ClassWriter(0)
|
||||
val enhancer = Proxy.newEnhancer(TestClass::class.java)
|
||||
val clazz = enhancer.createClass()
|
||||
CglibUtil.setStaticCallbacks(clazz, arrayOf(ProxyInterceptor()))
|
||||
val instance = clazz.newInstance()
|
||||
enhancer.generateClass(writer)
|
||||
File("TestClass.class").writeBytes(writer.toByteArray())
|
||||
}
|
||||
|
||||
@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 = Proxy.getCachedTarget(TestClass::class.java).newInstance()
|
||||
//val container = Proxy.injectCallback(t)
|
||||
//container as MutableProxyContainer
|
||||
container.addProxy(GetA(t))
|
||||
|
||||
println(t.javaClass)
|
||||
repeat(10) {
|
||||
t.a = t.a
|
||||
println(t.a)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun benchmark() {
|
||||
val (t, container) = Proxy.get<TestClass>()
|
||||
container.addProxy(GetA(t))
|
||||
|
||||
|
@ -91,41 +91,54 @@ object ReflectAsmUtils {
|
||||
returnType = method.returnType,
|
||||
)
|
||||
|
||||
inline fun <reified T, reified R> getMethod0(methodName: String): (T.() -> R)? {
|
||||
val (methodAccess, index) = getMethod(T::class.java, methodName, returnType = R::class.java)
|
||||
inline fun <reified T, reified R> getMethod0(
|
||||
methodName: String,
|
||||
type: Class<T> = T::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): (T.() -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, returnType = returnType)
|
||||
?: return null
|
||||
return {
|
||||
methodAccess.invoke(this, index) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T, reified A1, reified R> getMethod1(methodName: String): (T.(A1) -> R)? {
|
||||
val (methodAccess, index) = getMethod(T::class.java, methodName, A1::class.java, returnType = R::class.java)
|
||||
inline fun <reified T, reified A1, reified R> getMethod1(
|
||||
methodName: String,
|
||||
type: Class<T> = T::class.java,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): (T.(A1) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, returnType = returnType)
|
||||
?: return null
|
||||
return { a1 ->
|
||||
methodAccess.invoke(this, index, a1) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T, reified A1, reified A2, reified R> getMethod2(methodName: String): (T.(A1, A2) -> R)? {
|
||||
val (methodAccess, index) = getMethod(T::class.java,
|
||||
methodName,
|
||||
A1::class.java,
|
||||
A2::class.java,
|
||||
returnType = R::class.java)
|
||||
inline fun <reified T, reified A1, reified A2, reified R> getMethod2(
|
||||
methodName: String,
|
||||
type: Class<T> = T::class.java,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): (T.(A1, A2) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2 ->
|
||||
methodAccess.invoke(this, index, a1, a2) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T, reified A1, reified A2, reified A3, reified R> getMethod3(methodName: String): (T.(A1, A2, A3) -> R)? {
|
||||
val (methodAccess, index) = getMethod(T::class.java,
|
||||
methodName,
|
||||
A1::class.java,
|
||||
A2::class.java,
|
||||
A3::class.java,
|
||||
returnType = R::class.java)
|
||||
inline fun <reified T, reified A1, reified A2, reified A3, reified R> getMethod3(
|
||||
methodName: String,
|
||||
type: Class<T> = T::class.java,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
ta3: Class<A3> = A3::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): (T.(A1, A2, A3) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2, a3 ->
|
||||
methodAccess.invoke(this, index, a1, a2, a3) as R
|
||||
@ -133,14 +146,16 @@ object ReflectAsmUtils {
|
||||
}
|
||||
|
||||
inline fun <reified T, reified A1, reified A2, reified A3, reified A4, reified R>
|
||||
getMethod4(methodName: String): (T.(A1, A2, A3, A4) -> R)? {
|
||||
val (methodAccess, index) = getMethod(T::class.java,
|
||||
methodName,
|
||||
A1::class.java,
|
||||
A2::class.java,
|
||||
A3::class.java,
|
||||
A4::class.java,
|
||||
returnType = R::class.java)
|
||||
getMethod4(
|
||||
methodName: String,
|
||||
type: Class<T> = T::class.java,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
ta3: Class<A3> = A3::class.java,
|
||||
ta4: Class<A4> = A4::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): (T.(A1, A2, A3, A4) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2, a3, a4 ->
|
||||
methodAccess.invoke(this, index, a1, a2, a3, a4) as R
|
||||
@ -148,15 +163,17 @@ object ReflectAsmUtils {
|
||||
}
|
||||
|
||||
inline fun <reified T, reified A1, reified A2, reified A3, reified A4, reified A5, reified R>
|
||||
getMethod5(methodName: String): (T.(A1, A2, A3, A4, A5) -> R)? {
|
||||
val (methodAccess, index) = getMethod(T::class.java,
|
||||
methodName,
|
||||
A1::class.java,
|
||||
A2::class.java,
|
||||
A3::class.java,
|
||||
A4::class.java,
|
||||
A5::class.java,
|
||||
returnType = R::class.java)
|
||||
getMethod5(
|
||||
methodName: String,
|
||||
type: Class<T> = T::class.java,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
ta3: Class<A3> = A3::class.java,
|
||||
ta4: Class<A4> = A4::class.java,
|
||||
ta5: Class<A5> = A5::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): (T.(A1, A2, A3, A4, A5) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, ta5, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2, a3, a4, a5 ->
|
||||
methodAccess.invoke(this, index, a1, a2, a3, a4, a5) as R
|
||||
@ -164,19 +181,126 @@ object ReflectAsmUtils {
|
||||
}
|
||||
|
||||
inline fun <reified T, reified A1, reified A2, reified A3, reified A4, reified A5, reified A6, reified R>
|
||||
getMethod6(methodName: String): (T.(A1, A2, A3, A4, A5, A6) -> R)? {
|
||||
val (methodAccess, index) = getMethod(T::class.java,
|
||||
methodName,
|
||||
A1::class.java,
|
||||
A2::class.java,
|
||||
A3::class.java,
|
||||
A4::class.java,
|
||||
A5::class.java,
|
||||
A6::class.java,
|
||||
returnType = R::class.java)
|
||||
getMethod6(
|
||||
methodName: String,
|
||||
type: Class<T> = T::class.java,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
ta3: Class<A3> = A3::class.java,
|
||||
ta4: Class<A4> = A4::class.java,
|
||||
ta5: Class<A5> = A5::class.java,
|
||||
ta6: Class<A6> = A6::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): (T.(A1, A2, A3, A4, A5, A6) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, ta5, ta6, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2, a3, a4, a5, a6 ->
|
||||
methodAccess.invoke(this, index, a1, a2, a3, a4, a5, a6) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified R> getStaticMethod0(
|
||||
type: Class<*>,
|
||||
methodName: String,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): (() -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, returnType = returnType)
|
||||
?: return null
|
||||
return {
|
||||
methodAccess.invoke(null, index) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified A1, reified R> getStaticMethod1(
|
||||
type: Class<*>,
|
||||
methodName: String,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): ((A1) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, returnType = returnType)
|
||||
?: return null
|
||||
return { a1 ->
|
||||
methodAccess.invoke(null, index, a1) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified A1, reified A2, reified R> getStaticMethod2(
|
||||
type: Class<*>,
|
||||
methodName: String,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): ((A1, A2) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2 ->
|
||||
methodAccess.invoke(null, index, a1, a2) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified A1, reified A2, reified A3, reified R> getStaticMethod3(
|
||||
type: Class<*>,
|
||||
methodName: String,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
ta3: Class<A3> = A3::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): ((A1, A2, A3) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2, a3 ->
|
||||
methodAccess.invoke(null, index, a1, a2, a3) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified A1, reified A2, reified A3, reified A4, reified R> getStaticMethod4(
|
||||
type: Class<*>,
|
||||
methodName: String,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
ta3: Class<A3> = A3::class.java,
|
||||
ta4: Class<A4> = A4::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): ((A1, A2, A3, A4) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2, a3, a4 ->
|
||||
methodAccess.invoke(null, index, a1, a2, a3, a4) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified A1, reified A2, reified A3, reified A4, reified A5, reified R> getStaticMethod5(
|
||||
type: Class<*>,
|
||||
methodName: String,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
ta3: Class<A3> = A3::class.java,
|
||||
ta4: Class<A4> = A4::class.java,
|
||||
ta5: Class<A5> = A5::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): ((A1, A2, A3, A4, A5) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, ta5, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2, a3, a4, a5 ->
|
||||
methodAccess.invoke(null, index, a1, a2, a3, a4, a5) as R
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified A1, reified A2, reified A3, reified A4, reified A5, reified A6, reified R> getStaticMethod6(
|
||||
type: Class<*>,
|
||||
methodName: String,
|
||||
ta1: Class<A1> = A1::class.java,
|
||||
ta2: Class<A2> = A2::class.java,
|
||||
ta3: Class<A3> = A3::class.java,
|
||||
ta4: Class<A4> = A4::class.java,
|
||||
ta5: Class<A5> = A5::class.java,
|
||||
ta6: Class<A6> = A6::class.java,
|
||||
returnType: Class<R> = R::class.java,
|
||||
): ((A1, A2, A3, A4, A5, A6) -> R)? {
|
||||
val (methodAccess, index) = getMethod(type, methodName, ta1, ta2, ta3, ta4, ta5, ta6, returnType = returnType)
|
||||
?: return null
|
||||
return { a1, a2, a3, a4, a5, a6 ->
|
||||
methodAccess.invoke(null, index, a1, a2, a3, a4, a5, a6) as R
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class ExtSqlDialect(
|
||||
) : SqlDialect by sqlDialect {
|
||||
override fun createSqlFormatter(database: Database, beautifySql: Boolean, indentSize: Int): SqlFormatter {
|
||||
val formatter = sqlDialect.createSqlFormatter(database, beautifySql, indentSize)
|
||||
val (proxyFormatter, container) = Proxy[formatter.javaClass, InstantAllocator::get]
|
||||
val (proxyFormatter, container) = Proxy.get(formatter.javaClass) { InstantAllocator(it) }
|
||||
run {
|
||||
val extSqlFormatter = ExtSqlFormatter(formatter)
|
||||
extSqlFormatter.registerVisitor(DirectSqlExpression.visitor)
|
||||
|
Loading…
Reference in New Issue
Block a user