首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Kodein + Ktor =冷冻kotlin.collections.HashMap的突变尝试--为什么?

Kodein + Ktor =冷冻kotlin.collections.HashMap的突变尝试--为什么?
EN

Stack Overflow用户
提问于 2021-05-31 07:35:46
回答 2查看 1.4K关注 0票数 3

最近几天来,我一直在和这个例外作斗争。

我有一个具有以下依赖性的kotlin多平台项目:

  • kotlin=1.5.10
  • kodein=7.6.0
  • ktor=1.6.0 (使用kotlin coroutines 1.5.0-本机-mt内部)

在尝试在本机中使用httpClient时,我一直被提到异常:

代码语言:javascript
复制
    at kotlin.Throwable#<init>(/Users/teamcity3/buildAgent/work/290aee0e088a1666/runtime/src/main/kotlin/kotlin/Throwable.kt:23)
    at kotlin.Exception#<init>(/Users/teamcity3/buildAgent/work/290aee0e088a1666/runtime/src/main/kotlin/kotlin/Exceptions.kt:23)
    at kotlin.RuntimeException#<init>(/Users/teamcity3/buildAgent/work/290aee0e088a1666/runtime/src/main/kotlin/kotlin/Exceptions.kt:34)
    at kotlin.native.concurrent.InvalidMutabilityException#<init>(/Users/teamcity3/buildAgent/work/290aee0e088a1666/runtime/src/main/kotlin/kotlin/native/concurrent/Freezing.kt:22)
    at <global>.ThrowInvalidMutabilityException(/Users/teamcity3/buildAgent/work/290aee0e088a1666/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt:93)
    at <global>.MutationCheck(Unknown Source)
    at kotlin.collections.HashMap.<set-length>#internal(/Users/teamcity3/buildAgent/work/290aee0e088a1666/runtime/src/main/kotlin/kotlin/collections/HashMap.kt:16)
    at kotlin.collections.HashMap#addKey(/Users/teamcity3/buildAgent/work/290aee0e088a1666/runtime/src/main/kotlin/kotlin/collections/HashMap.kt:292)
    at kotlin.collections.HashMap#put(/Users/teamcity3/buildAgent/work/290aee0e088a1666/runtime/src/main/kotlin/kotlin/collections/HashMap.kt:68)
    at org.kodein.di.internal.DITreeImpl#find(/Users/runner/work/Kodein-DI/Kodein-DI/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DITreeImpl.kt:132)
    at org.kodein.di.DITree#find$default(/Users/runner/work/Kodein-DI/Kodein-DI/kodein-di/src/commonMain/kotlin/org/kodein/di/DITree.kt:36)
    at org.kodein.di.internal.DIContainerImpl#factory(/Users/runner/work/Kodein-DI/Kodein-DI/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DIContainerImpl.kt:158)
    at org.kodein.di.DIContainer#factory$default(/Users/runner/work/Kodein-DI/Kodein-DI/kodein-di/src/commonMain/kotlin/org/kodein/di/DIContainer.kt:32)
    at org.kodein.di.DIContainer#provider(/Users/runner/work/Kodein-DI/Kodein-DI/kodein-di/src/commonMain/kotlin/org/kodein/di/DIContainer.kt:76)
    at org.kodein.di.DIContainer#provider$default(/Users/runner/work/Kodein-DI/Kodein-DI/kodein-di/src/commonMain/kotlin/org/kodein/di/DIContainer.kt:75)
    at org.kodein.di.internal.DirectDIBaseImpl#Instance(/Users/runner/work/Kodein-DI/Kodein-DI/kodein-di/src/commonMain/kotlin/org/kodein/di/internal/DirectDIImpl.kt:30)
    at InvalidMutabilitySampleTest.<init>$lambda-6$lambda-5$lambda-4$lambda-3$lambda-2#internal(/Users/r.juszczyk/StudioProjects/lmhu-multiplatform-app/MultiplatformApp/src/iosTest/kotlin/InvalidMutabilitySampleTest.kt:26)
    at InvalidMutabilitySampleTest.$<init>$lambda-6$lambda-5$lambda-4$lambda-3$lambda-2$FUNCTION_REFERENCE$3.invoke#internal(/Users/r.juszczyk/StudioProjects/lmhu-multiplatform-app/MultiplatformApp/src/iosTest/kotlin/InvalidMutabilitySampleTest.kt:25)
    at InvalidMutabilitySampleTest.$<init>$lambda-6$lambda-5$lambda-4$lambda-3$lambda-2$FUNCTION_REFERENCE$3.$<bridge-UNNN>invoke(/Users/r.juszczyk/StudioProjects/lmhu-multiplatform-app/MultiplatformApp/src/iosTest/kotlin/InvalidMutabilitySampleTest.kt:25)
    at io.ktor.client.HttpClientConfig.install$<anonymous>_1#internal(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClientConfig.kt:69)
    at io.ktor.client.HttpClientConfig.$install$<anonymous>_1$FUNCTION_REFERENCE$17.invoke#internal(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClientConfig.kt:65)
    at io.ktor.client.HttpClientConfig.$install$<anonymous>_1$FUNCTION_REFERENCE$17.$<bridge-UNNN>invoke(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClientConfig.kt:65)
    at io.ktor.client.features.json.JsonFeature.Feature#prepare(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-features/ktor-client-json/common/src/io/ktor/client/features/json/JsonFeature.kt:129)
    at io.ktor.client.HttpClientConfig.install$<anonymous>_1-2#internal(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClientConfig.kt:77)
    at io.ktor.client.HttpClientConfig.$install$<anonymous>_1-2$FUNCTION_REFERENCE$18.invoke#internal(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClientConfig.kt:74)
    at io.ktor.client.HttpClientConfig.$install$<anonymous>_1-2$FUNCTION_REFERENCE$18.$<bridge-UNNN>invoke(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClientConfig.kt:74)
    at io.ktor.client.HttpClientConfig#install(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClientConfig.kt:97)
    at io.ktor.client.HttpClient#<init>(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClient.kt:172)
    at io.ktor.client.HttpClient#<init>(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClient.kt:81)
    at io.ktor.client#HttpClient(/Users/administrator/Documents/agent/work/8d547b974a7be21f/ktor-client/ktor-client-core/common/src/io/ktor/client/HttpClient.kt:43)

我在一次测试中成功地再现了那次坠机:

代码语言:javascript
复制
class InvalidMutabilitySampleTest {
    val di = DI {
        import(DI.Module("Some Module") {
            bind<Json>() with provider {
                Json {
                    prettyPrint = true
                    isLenient = true
                }
            }

            bind<HttpClient>() with provider {
                HttpClient{
                    install(JsonFeature) {
                        serializer = KotlinxSerializer(instance())
                    }
                }
            }
        })
    }

    val httpClient: HttpClient by di.instance()

    @Test
    fun invalidMutabilityTest() {
        println(httpClient)
    }

}

我还通过更改来修复它:

代码语言:javascript
复制
HttpClient{
   install(JsonFeature) {
      serializer = KotlinxSerializer(instance())
   }
}

至:

代码语言:javascript
复制
val json = instance<Json>()
HttpClient{
   install(JsonFeature) {
      serializer = KotlinxSerializer(json)
   }
}

然后我注意到HttpClient做了一件非常具体的事情--它将自己冻结在init块中。我成功地用以下示例代码再现了它:

代码语言:javascript
复制
class FrozenConstructor(val block: ()->Unit) {
    init {
        freeze()
    }
}

class InvalidMutabilitySampleTest2 {
    val di = DI {
        import(DI.Module("Some Module") {
            bind<String>() with provider {
                "lolo"
            }

            bind<FrozenConstructor>() with provider {
                FrozenConstructor{
                    instance<String>()
                }
            }
        })
    }

    val frozenConstructor: FrozenConstructor by di.instance()

    @Test
    fun invalidMutabilityTest() {
        println(frozenConstructor)
    }
}

所以我的理论是:

试图提供class

  • FrozenConstructor
  1. kodein被创建并冻结了自己,它的成员引用kodein
  2. kodein试图缓存提供的依赖,并尝试改变内部MutableMap,而内部MutableMap被冻结,一切都崩溃了

有人能确认这或多或少是正确的吗?如果不正确,可以纠正我吗?

另外,你们能提出最好的解决方法吗?还有其他等待解决的陷阱?

是科丁虫吗?

如果我使用的是with provider而不是with singleton,为什么kodein必须将一些东西存储在可变的地图中?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-05-31 13:52:22

我想你已经猜到了。Ktor冻结了自己和它的所有配置,以确保它可以在Kotlin/原住民中的线程之间使用。Kodein假设您只会从一个线程中触摸到它,并且不安全。(无论这是一个限制、一个bug,还是一个设计缺陷,都可能有待解释。)

为了解决这些问题,您希望避免意外地捕获指向Kodein内部的this配置中的HttpClient引用。这样做的一个好方法是从HttpClient lambda之外的助手变量中获取DI中的实例,正如您已经发现的那样。

票数 6
EN

Stack Overflow用户

发布于 2021-06-01 14:19:58

你是对的。FrozenConstructor冻结自己,因此它的block属性,作为一个lambda,冻结它的所有捕获,其中包括DI容器。

Kodein不支持冻结(因此也不支持原生多线程)。自从JB宣布要开发一个新的GC之后,这个决定已经决定不投资于使它与本地的多层兼容。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67769611

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档