You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现KCache缓存初始化的泛型化,适配不同存储对象类型

解决方案

Kotlin可以通过实化类型参数(reified) 解决泛型擦除导致无法获取T实际类型的问题,配合工厂方法即可完成初始化逻辑的泛型化,具体实现如下:

方案1:使用实化类型参数的工厂方法(推荐)

Kotlin的inline函数支持reified修饰的泛型参数,编译期会自动替换为实际调用的类型,运行时可直接读取类型信息,不需要手动传递类型对象。我们可以将构造器私有化,通过伴生对象的inline工厂方法来实例化MyCache:

import org.apache.kafka.common.serialization.Serde
import org.apache.kafka.common.serialization.Serdes
import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig
import io.confluent.kafka.streams.serdes.avro.SpecificAvroSerde
import org.apache.avro.specific.SpecificRecord
import java.util.*
import kotlin.collections.sortedMapOf

// 构造器私有化,仅通过工厂方法实例化
class MyCache<T> private constructor(
    private val cache: SortedMap<String, T>
) : SortedMap<String, T> by cache { // 委托实现SortedMap接口,对外直接暴露缓存操作能力

    companion object {
        // 带实化泛型参数的工厂方法
        inline fun <reified T> create(name: String, test: Boolean = true, appConfig: AppConfig): MyCache<T> {
            val cache = if (test) {
                sortedMapOf<String, T>()
            } else {
                val cacheProps = Properties()
                cacheProps[KafkaCacheConfig.KAFKACACHE_BOOTSTRAP_SERVERS_CONFIG] =
                    appConfig.propertyOrNull("kafka.bootstrapServers")?.getString()
                cacheProps[KafkaCacheConfig.KAFKACACHE_GROUP_ID_CONFIG] =
                    appConfig.propertyOrNull("applicationId")?.getString()
                cacheProps[KafkaCacheConfig.KAFKACACHE_CLIENT_ID_CONFIG] = "GeneratingUnitsCache"
                cacheProps[KafkaCacheConfig.KAFKACACHE_TOPIC_CONFIG] = "app.$name.kcache"

                val serdeConfig = Collections.singletonMap(
                    AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG,
                    appConfig.property("kafka.schemaRegistryUrl").getString(),
                )

                // 根据实际类型匹配对应Serde,可扩展更多类型分支
                val valueSerde: Serde<T> = when {
                    T::class == String::class -> Serdes.String() as Serde<T>
                    SpecificRecord::class.java.isAssignableFrom(T::class.java) -> {
                        SpecificAvroSerde<T>().apply {
                            configure(serdeConfig, false)
                        }
                    }
                    else -> throw IllegalArgumentException("不支持的缓存值类型:${T::class.simpleName}")
                }

                KafkaCache(
                    KafkaCacheConfig(cacheProps),
                    Serdes.String(),
                    valueSerde
                ).apply { init() }
            }
            return MyCache(cache)
        }
    }
}

调用方式非常简洁:

// 初始化存储MyAvroObject的缓存
val avroCache = MyCache.create<MyAvroObject>("avro-cache", test = false, appConfig)
// 初始化存储String的缓存
val stringCache = MyCache.create<String>("string-cache", test = false, appConfig)

方案2:构造器传入Class(兼容非inline场景)

如果业务场景不适合使用inline函数,可以手动在构造时传递类型的Class对象实现同样的逻辑:

class MyCache<T>(
    name: String,
    test: Boolean = true,
    appConfig: AppConfig,
    valueType: Class<T>
) {
    private val cache: SortedMap<String, T>

    init {
        cache = if (test) {
            sortedMapOf()
        } else {
            // 公共配置初始化逻辑和方案1完全一致,此处省略
            val valueSerde: Serde<T> = when {
                valueType == String::class.java -> Serdes.String() as Serde<T>
                SpecificRecord::class.java.isAssignableFrom(valueType) -> {
                    SpecificAvroSerde<T>().apply { configure(serdeConfig, false) }
                }
                else -> throw IllegalArgumentException("不支持的缓存值类型:${valueType.simpleName}")
            }
            KafkaCache(KafkaCacheConfig(cacheProps), Serdes.String(), valueSerde).apply { init() }
        }
    }
}

调用方式:

val avroCache = MyCache("avro-cache", false, appConfig, MyAvroObject::class.java)

内容的提问来源于stack exchange,提问作者hermanjakobsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 02:06:02