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

手动配置Spring Data R2DBC遇无法访问字段错误求助

问题描述

应用需要连接两个数据库,因此手动配置R2DBC。单数据库自动配置时仓库可正常工作,但手动配置创建仓库实现时报错:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.String java.net.URL.protocol accessible: module java.base does not "opens java.net" to unnamed module @69a61a00

实体包含类型为URL的属性,配置代码如下:

@Configuration
@EnableR2dbcRepositories(
    entityOperationsRef = "postgresR2dbcEntityOperations",
    basePackages = ["com.acme.somepackage"],
)
@EnableR2dbcAuditing
class R2DBCConfiguration {
    @Bean
    @ConfigurationProperties("spring.r2dbc.postgres")
    fun postgresR2dbcProperties() = R2dbcProperties()

    @Bean
    fun postgresConnectionFactory(
        @Qualifier("postgresR2dbcProperties") props: R2dbcProperties
    ): ConnectionFactory {
        val host = ConnectionFactoryOptions
            .parse(props.url)
            .getRequiredValue(Option.valueOf<String>("host")) as String

        return PostgresqlConnectionConfiguration
            .builder()
            .host(host)
            .username(props.username)
            .password(props.password)
            .schema("myschema")
            .build()
            .let { PostgresqlConnectionFactory(it) }
    }

    @Bean
    fun postgresR2dbcEntityOperations(
        @Qualifier("postgresConnectionFactory") connectionFactory: ConnectionFactory,
    ): R2dbcEntityOperations {
        val mappingContext = R2dbcMappingContext()
        val dialect = DialectResolver.getDialect(connectionFactory)
        val converters = dialect.converters.toMutableList()
        converters.addAll(R2dbcCustomConversions.STORE_CONVERTERS)

        val storeConversions = StoreConversions.of(dialect.getSimpleTypeHolder(), converters)
        val customConverters = listOf(
            // customer converters
        )
        val customConversions = R2dbcCustomConversions(storeConversions, customConverters)
        val mappingConverter = MappingR2dbcConverter(mappingContext, customConversions)
        val strategy = DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE, mappingConverter)
        val client = DatabaseClient.builder()
            .connectionFactory(connectionFactory)
            .bindMarkers(PostgresDialect.INSTANCE.bindMarkersFactory)
            .build()

        return R2dbcEntityTemplate(client, strategy)
    }
}

完整堆栈信息:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.String java.net.URL.protocol accessible: module java.base does not "opens java.net" to unnamed module @69a61a00
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
    at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
    at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:779)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:536)
    at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:703)
    at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:422)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:379)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.lambda$createAndRegisterProperty$3(AbstractMappingContext.java:591)
    at java.base/java.lang.Iterable.forEach(Iterable.java:75)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:588)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:542)
    at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:703)
    at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:422)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:379)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:280)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:206)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:92)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$6(RepositoryFactoryBeanSupport.java:282)
    at java.base/java.util.Optional.ifPresent(Optional.java:178)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:282)
    at org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean.afterPropertiesSet(R2dbcRepositoryFactoryBean.java:159)

请问自动配置中存在哪些我未实现的配置可以解决该问题?


解决方案

问题根源是手动配置时缺少了Spring R2DBC自动配置默认处理的URL类型映射逻辑,导致Spring Data尝试反射访问URL的私有字段触发模块访问限制。自动配置帮你做了这些关键配置,你需要手动补上:

  1. 添加URL与String的默认转换器
    Spring R2DBC自动配置会默认注册UrlToStringConverter和StringToUrlConverter,这两个转换器能让URL类型直接与数据库字符串字段映射,避免Spring Data去解析URL私有属性。把它们加入自定义转换器列表:
import org.springframework.data.convert.StringToUrlConverter
import org.springframework.data.convert.UrlToStringConverter

// ...
val customConverters = listOf(
    UrlToStringConverter(),
    StringToUrlConverter()
)
// ...
  1. 正确初始化R2dbcMappingContext
    自动配置会为R2dbcMappingContext设置正确的类型持有者,确保类型识别逻辑正常。修改映射上下文的初始化代码:
val mappingContext = R2dbcMappingContext().apply {
    setSimpleTypeHolder(customConversions.simpleTypeHolder)
}
  1. 使用动态解析的方言而非硬编码
    你的代码硬编码了PostgresDialect.INSTANCE,但自动配置会根据连接工厂动态获取方言,确保兼容性。修改数据访问策略的初始化:
val strategy = DefaultReactiveDataAccessStrategy(dialect, mappingConverter)

把这些修改整合到postgresR2dbcEntityOperations方法中,就能和自动配置的行为保持一致,解决反射访问URL私有字段的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 00:12:03