make Proxy run faster

This commit is contained in:
tursom 2022-04-09 23:04:50 +08:00
parent 68648b1f77
commit 56375ce172
13 changed files with 392 additions and 163 deletions

View File

@ -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)
}
}

View File

@ -6,27 +6,40 @@ import net.sf.cglib.proxy.Factory
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
object Proxy { 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 val cache = ConcurrentHashMap<Class<*>, Class<*>>()
private fun <T> getTarget(clazz: Class<T>): Class<T> = cache.computeIfAbsent(clazz) { fun getContainer(obj: Any): ProxyContainer? {
val enhancer = Enhancer() if (obj !is Factory) return null
enhancerMap[clazz] = enhancer val interceptor = obj.getCallback(0) as? ProxyInterceptor ?: return null
enhancer.setSuperclass(clazz) return interceptor.container
enhancer.setCallbackType(ProxyInterceptor::class.java) }
enhancer.setCallbackFilter { 0 }
enhancer.createClass()
}.uncheckedCast()
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>, clazz: Class<T>,
container: MutableProxyContainer = defaultContainer(),
builder: (Class<T>) -> T, builder: (Class<T>) -> T,
): Pair<T, MutableProxyContainer> { ): Pair<T, MutableProxyContainer> {
val target = getTarget(clazz) val target = getCachedTarget(clazz)
val container = ListProxyContainer()
val obj = builder(target) val obj = builder(target)
obj as Factory injectCallback(obj as Factory) { container }
obj.setCallback(0, ProxyInterceptor(container))
return obj to container return obj to container
} }
@ -34,15 +47,42 @@ object Proxy {
inline fun <reified T> get( inline fun <reified T> get(
argumentTypes: Array<out Class<*>>, argumentTypes: Array<out Class<*>>,
arguments: Array<out Any?>, 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( operator fun <T> get(
clazz: Class<T>, clazz: Class<T>,
argumentTypes: Array<out Class<*>>, argumentTypes: Array<out Class<*>>,
arguments: Array<out Any?>, arguments: Array<out Any?>,
) = get(clazz) { container: MutableProxyContainer = defaultContainer(),
) = get(clazz, container) {
it.getConstructor(*argumentTypes).newInstance(*arguments) 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()
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -2,39 +2,16 @@ package cn.tursom.proxy
import net.sf.cglib.proxy.MethodInterceptor import net.sf.cglib.proxy.MethodInterceptor
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
import java.lang.reflect.Field
import java.lang.reflect.Method import java.lang.reflect.Method
import java.util.*
class ProxyInterceptor( class ProxyInterceptor(
private val container: ProxyContainer = ListProxyContainer(), val container: ProxyContainer = ListProxyContainer(),
// disable call super can save 20% time
private val supportCallSuper: Boolean = true, private val supportCallSuper: Boolean = true,
) : MethodInterceptor { ) : 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? { override fun intercept(obj: Any, method: Method, args: Array<out Any?>, proxy: MethodProxy): Any? {
if (supportCallSuper && callSuper.get() == true) { if (supportCallSuper && Proxy.callSuper.get()) {
callSuper.remove() Proxy.callSuper.remove()
return proxy.invokeSuper(obj, args) return proxy.invokeSuper(obj, args)
} }
@ -45,4 +22,4 @@ class ProxyInterceptor(
proxy.invokeSuper(obj, args) proxy.invokeSuper(obj, args)
} }
} }
} }

View File

@ -9,12 +9,12 @@ import java.util.concurrent.ConcurrentHashMap
interface ProxyMethod { interface ProxyMethod {
@Throws(Throwable::class) @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 handlerCacheMap = getHandlerCacheMap(javaClass)
val methodResult = handlerCacheMap[method] val methodResult = handlerCacheMap[method]
if (methodResult != null) { if (methodResult != null) {
return if (methodResult.success) { return if (methodResult.success) {
ProxyResult.of(methodResult.result(this, args)) methodResult.result(this, args)
} else { } else {
ProxyResult.failed<Any>() ProxyResult.failed<Any>()
} }
@ -34,7 +34,7 @@ interface ProxyMethod {
if (reflectAsmMethod != null) { if (reflectAsmMethod != null) {
val (methodAccess, index) = reflectAsmMethod val (methodAccess, index) = reflectAsmMethod
handlerCacheMap[method] = ProxyResult({ p, a -> handlerCacheMap[method] = ProxyResult({ p, a ->
methodAccess.invoke(p, index, *a) ProxyResult.of(methodAccess.invoke(p, index, *a))
}, true) }, true)
return ProxyResult.of(methodAccess.invoke(this, index, *args)) return ProxyResult.of(methodAccess.invoke(this, index, *args))
} }
@ -58,7 +58,7 @@ interface ProxyMethod {
selfMethod = javaClass.getMethod(methodName, *method.parameterTypes) selfMethod = javaClass.getMethod(methodName, *method.parameterTypes)
selfMethod.isAccessible = true selfMethod.isAccessible = true
handlerCacheMap[method] = ProxyResult({ p, a -> handlerCacheMap[method] = ProxyResult({ p, a ->
selfMethod(p, *a) ProxyResult.of(selfMethod(p, *a))
}, true) }, true)
return ProxyResult.of<Any>(selfMethod(this, *args)) return ProxyResult.of<Any>(selfMethod(this, *args))
} catch (_: Exception) { } catch (_: Exception) {
@ -70,11 +70,11 @@ interface ProxyMethod {
companion object { companion object {
private val handlerCacheMapMap: MutableMap< private val handlerCacheMapMap: MutableMap<
Class<out ProxyMethod>, Class<out ProxyMethod>,
MutableMap<Method, ProxyResult<(proxy: ProxyMethod, args: Array<out Any?>) -> Any?>>> = MutableMap<Method, ProxyResult<(proxy: ProxyMethod, args: Array<out Any?>) -> ProxyResult<*>>>> =
HashMap() 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] var handlerCacheMap = handlerCacheMapMap[type]
if (handlerCacheMap == null) synchronized(handlerCacheMapMap) { if (handlerCacheMap == null) synchronized(handlerCacheMapMap) {
handlerCacheMap = handlerCacheMapMap[type] handlerCacheMap = handlerCacheMapMap[type]

View File

@ -2,31 +2,34 @@ package cn.tursom.proxy
import net.sf.cglib.proxy.MethodProxy import net.sf.cglib.proxy.MethodProxy
import java.lang.reflect.Method 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( class ProxyMethodCache(
private var lastModify: Long = 0, private var lastModify: Long = 0,
private var function: ProxyMethodCacheFunction = failed,
) { ) {
companion object { 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.lastModify = lastModify
this.function = function functionMap[proxy] = function
} }
operator fun invoke( operator fun invoke(
lastModify: Long, lastModify: Long,
obj: Any?, obj: Any,
c: ProxyContainer,
method: Method, method: Method,
args: Array<out Any?>, args: Array<out Any?>,
proxy: MethodProxy, proxy: MethodProxy,
): ProxyResult<*>? = if (lastModify != this.lastModify) { ): ProxyResult<*>? = if (lastModify != this.lastModify) {
null null
} else { } else {
function(obj, method, args, proxy) (functionMap[proxy] ?: failed)(obj, c, method, args, proxy)
} }
} }

View File

@ -5,7 +5,7 @@ import cn.tursom.core.uncheckedCast
data class ProxyResult<out R>( data class ProxyResult<out R>(
val result: R, val result: R,
val success: Boolean = false, val success: Boolean = false,
val cache: Boolean = false, val cache: Boolean = true,
) { ) {
companion object { companion object {
val success: ProxyResult<*> = ProxyResult<Any?>(null, true) val success: ProxyResult<*> = ProxyResult<Any?>(null, true)

View File

@ -12,10 +12,8 @@ import java.util.*
object ProxyRunner { object ProxyRunner {
private val errMsgSearchList = arrayOf("%M", "%B", "%A") private val errMsgSearchList = arrayOf("%M", "%B", "%A")
private val forFirstProxyCacheKey = private val proxyMethodCacheKey = ProxyContainer.contextEnv.newKey<ProxyMethodCache>()
ProxyContainer.contextEnv.newKey<ProxyMethodCache>().withDefault { ProxyMethodCache() } .withDefault { ProxyMethodCache() }
private val forEachProxyCacheKey =
ProxyContainer.contextEnv.newKey<ProxyMethodCache>().withDefault { ProxyMethodCache() }
/** /**
* will be call when proxy method invoke. * will be call when proxy method invoke.
@ -23,10 +21,12 @@ object ProxyRunner {
*/ */
@Throws(Throwable::class) @Throws(Throwable::class)
fun onProxy(obj: Any, c: ProxyContainer, method: Method, args: Array<out Any?>, proxy: MethodProxy): ProxyResult<*> { fun onProxy(obj: Any, c: ProxyContainer, method: Method, args: Array<out Any?>, proxy: MethodProxy): ProxyResult<*> {
var handler = ProxyContainerHandlerCache.getHandler(proxy) val cache = c.context[proxyMethodCacheKey]
if (handler != null) { cache(c.lastModify, obj, c, method, args, proxy)?.let {
return handler(obj, c, method, args, proxy) return it
} }
var handler: ProxyMethodCacheFunction? = null
for (annotation in method.annotations) when (annotation) { for (annotation in method.annotations) when (annotation) {
is ForEachProxy -> { is ForEachProxy -> {
handler = onForeachProxy(annotation) handler = onForeachProxy(annotation)
@ -41,18 +41,17 @@ object ProxyRunner {
//handler = ProxyContainerHandlerCache.callSuper //handler = ProxyContainerHandlerCache.callSuper
handler = onForFirstProxy(ForFirstProxy.EMPTY) handler = onForFirstProxy(ForFirstProxy.EMPTY)
} }
ProxyContainerHandlerCache.setHandler(proxy, handler)
return handler(obj, c, method, args, proxy) return handler(obj, c, method, args, proxy)
} }
private fun onForFirstProxy(forFirstProxy: ForFirstProxy): (Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<*> { fun onForFirstProxy(forFirstProxy: ForFirstProxy): ProxyMethodCacheFunction {
return { o: Any, c: ProxyContainer, m: Method, a: Array<out Any?>, p: MethodProxy -> val classes = when (forFirstProxy.value.size) {
c.context[forFirstProxyCacheKey](c.lastModify, o, m, a, p) ?: onForFirstProxy(o, c, m, a, p, forFirstProxy, 0 -> emptyList()
when (forFirstProxy.value.size) { 1 -> listOf(forFirstProxy.value[0].java)
0 -> emptyList() else -> forFirstProxy.value.asSequence().map { it.java }.toSet()
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, forFirstProxy: ForFirstProxy,
classes: Collection<Class<*>>, classes: Collection<Class<*>>,
): ProxyResult<*> { ): ProxyResult<*> {
val cache = container.context[forFirstProxyCacheKey]
val result = container.forFirstProxy { p -> val result = container.forFirstProxy { p ->
if (classes.isEmpty() || classes.stream().anyMatch { c: Class<*> -> c.isInstance(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) { 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 return@forFirstProxy result
} else { } else {
@ -103,34 +101,48 @@ object ProxyRunner {
errMsg = StringUtils.replaceEach(errMsg, errMsgSearchList, replacementList) errMsg = StringUtils.replaceEach(errMsg, errMsgSearchList, replacementList)
val exceptionConstructor = forFirstProxy.errClass.java.getConstructor(String::class.java) val exceptionConstructor = forFirstProxy.errClass.java.getConstructor(String::class.java)
if (forFirstProxy.cache) { if (forFirstProxy.cache) {
cache.update(container.lastModify) { _, _, _, _ -> container.context[proxyMethodCacheKey].update(container.lastModify, proxy) { _, _, _, _, _ ->
throw exceptionConstructor.newInstance(errMsg) throw exceptionConstructor.newInstance(errMsg)
} }
} }
throw exceptionConstructor.newInstance(errMsg) throw exceptionConstructor.newInstance(errMsg)
} }
if (forFirstProxy.cache) { if (forFirstProxy.cache) {
cache.update(container.lastModify) container.context[proxyMethodCacheKey].update(container.lastModify, proxy)
} }
return ProxyResult.failed return ProxyResult.failed
} }
private fun onForeachProxy(forEachProxy: ForEachProxy) = onForeachProxy(when (forEachProxy.value.size) { fun onForeachProxy(forEachProxy: ForEachProxy) = onForeachProxy(when (forEachProxy.value.size) {
0 -> emptyList() 0 -> emptyList()
1 -> listOf(forEachProxy.value[0].java) 1 -> listOf(forEachProxy.value[0].java)
else -> forEachProxy.value.asSequence().map { it.java }.toSet() else -> forEachProxy.value.asSequence().map { it.java }.toSet()
}) }, forEachProxy.cache)
private val emptyProxyList = ArrayList<ProxyMethod>()
private fun onForeachProxy( private fun onForeachProxy(
classes: Collection<Class<*>>, classes: Collection<Class<*>>,
): (Any, ProxyContainer, Method, Array<out Any?>, MethodProxy) -> ProxyResult<Any?> { cache: Boolean,
return (label@{ o: Any, c: ProxyContainer, m: Method, a: Array<out Any?>, proxy1: MethodProxy -> ): ProxyMethodCacheFunction = { o, c, m, a, proxy ->
c.forEachProxy { p -> val proxyList = if (cache) ArrayList<ProxyMethod>() else emptyProxyList
if (classes.isEmpty() || classes.any { c: Class<*> -> c.isInstance(p) }) { c.forEachProxy { p ->
p.onProxy(o, m, a, proxy1) 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?>()
} }
} }

View File

@ -4,4 +4,8 @@ import kotlin.reflect.KClass
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME) @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,
)

View File

@ -1,6 +1,8 @@
package cn.tursom.proxy package cn.tursom.proxy
import org.junit.Test import org.junit.Test
import org.objectweb.asm.ClassWriter
import java.io.File
class Example { class Example {
open class TestClass protected constructor() { open class TestClass protected constructor() {
@ -12,14 +14,54 @@ class Example {
private val t: TestClass, private val t: TestClass,
) : ProxyMethod { ) : ProxyMethod {
fun getA(): Int { fun getA(): Int {
ProxyInterceptor.callSuper.set(true) Proxy.callSuper.set(true)
return t.a + 1 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 @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 = 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>() val (t, container) = Proxy.get<TestClass>()
container.addProxy(GetA(t)) container.addProxy(GetA(t))

View File

@ -91,41 +91,54 @@ object ReflectAsmUtils {
returnType = method.returnType, returnType = method.returnType,
) )
inline fun <reified T, reified R> getMethod0(methodName: String): (T.() -> R)? { inline fun <reified T, reified R> getMethod0(
val (methodAccess, index) = getMethod(T::class.java, methodName, returnType = R::class.java) 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 null
return { return {
methodAccess.invoke(this, index) as R methodAccess.invoke(this, index) as R
} }
} }
inline fun <reified T, reified A1, reified R> getMethod1(methodName: String): (T.(A1) -> R)? { inline fun <reified T, reified A1, reified R> getMethod1(
val (methodAccess, index) = getMethod(T::class.java, methodName, A1::class.java, returnType = R::class.java) 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 null
return { a1 -> return { a1 ->
methodAccess.invoke(this, index, a1) as R methodAccess.invoke(this, index, a1) as R
} }
} }
inline fun <reified T, reified A1, reified A2, reified R> getMethod2(methodName: String): (T.(A1, A2) -> R)? { inline fun <reified T, reified A1, reified A2, reified R> getMethod2(
val (methodAccess, index) = getMethod(T::class.java, methodName: String,
methodName, type: Class<T> = T::class.java,
A1::class.java, ta1: Class<A1> = A1::class.java,
A2::class.java, ta2: Class<A2> = A2::class.java,
returnType = R::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 null
return { a1, a2 -> return { a1, a2 ->
methodAccess.invoke(this, index, a1, a2) as R 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)? { inline fun <reified T, reified A1, reified A2, reified A3, reified R> getMethod3(
val (methodAccess, index) = getMethod(T::class.java, methodName: String,
methodName, type: Class<T> = T::class.java,
A1::class.java, ta1: Class<A1> = A1::class.java,
A2::class.java, ta2: Class<A2> = A2::class.java,
A3::class.java, ta3: Class<A3> = A3::class.java,
returnType = R::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 null
return { a1, a2, a3 -> return { a1, a2, a3 ->
methodAccess.invoke(this, index, a1, a2, a3) as R 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> inline fun <reified T, reified A1, reified A2, reified A3, reified A4, reified R>
getMethod4(methodName: String): (T.(A1, A2, A3, A4) -> R)? { getMethod4(
val (methodAccess, index) = getMethod(T::class.java, methodName: String,
methodName, type: Class<T> = T::class.java,
A1::class.java, ta1: Class<A1> = A1::class.java,
A2::class.java, ta2: Class<A2> = A2::class.java,
A3::class.java, ta3: Class<A3> = A3::class.java,
A4::class.java, ta4: Class<A4> = A4::class.java,
returnType = R::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 null
return { a1, a2, a3, a4 -> return { a1, a2, a3, a4 ->
methodAccess.invoke(this, index, a1, a2, a3, a4) as R 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> 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)? { getMethod5(
val (methodAccess, index) = getMethod(T::class.java, methodName: String,
methodName, type: Class<T> = T::class.java,
A1::class.java, ta1: Class<A1> = A1::class.java,
A2::class.java, ta2: Class<A2> = A2::class.java,
A3::class.java, ta3: Class<A3> = A3::class.java,
A4::class.java, ta4: Class<A4> = A4::class.java,
A5::class.java, ta5: Class<A5> = A5::class.java,
returnType = R::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 null
return { a1, a2, a3, a4, a5 -> return { a1, a2, a3, a4, a5 ->
methodAccess.invoke(this, index, a1, a2, a3, a4, a5) as R 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> 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)? { getMethod6(
val (methodAccess, index) = getMethod(T::class.java, methodName: String,
methodName, type: Class<T> = T::class.java,
A1::class.java, ta1: Class<A1> = A1::class.java,
A2::class.java, ta2: Class<A2> = A2::class.java,
A3::class.java, ta3: Class<A3> = A3::class.java,
A4::class.java, ta4: Class<A4> = A4::class.java,
A5::class.java, ta5: Class<A5> = A5::class.java,
A6::class.java, ta6: Class<A6> = A6::class.java,
returnType = R::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 null
return { a1, a2, a3, a4, a5, a6 -> return { a1, a2, a3, a4, a5, a6 ->
methodAccess.invoke(this, index, a1, a2, a3, a4, a5, a6) as R 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
}
}
} }

View File

@ -13,7 +13,7 @@ class ExtSqlDialect(
) : SqlDialect by sqlDialect { ) : SqlDialect by sqlDialect {
override fun createSqlFormatter(database: Database, beautifySql: Boolean, indentSize: Int): SqlFormatter { override fun createSqlFormatter(database: Database, beautifySql: Boolean, indentSize: Int): SqlFormatter {
val formatter = sqlDialect.createSqlFormatter(database, beautifySql, indentSize) 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 { run {
val extSqlFormatter = ExtSqlFormatter(formatter) val extSqlFormatter = ExtSqlFormatter(formatter)
extSqlFormatter.registerVisitor(DirectSqlExpression.visitor) extSqlFormatter.registerVisitor(DirectSqlExpression.visitor)