使用 DNS 记录(SRV 和 TXT)时,无法在 Spring 上下文中实例化 Mongo 相关 bean

Posted

技术标签:

【中文标题】使用 DNS 记录(SRV 和 TXT)时,无法在 Spring 上下文中实例化 Mongo 相关 bean【英文标题】:Unable to instantiate Mongo related beans in Spring context when DNS records (SRV and TXT) are being used 【发布时间】:2021-12-27 07:34:38 【问题描述】:

我在没有任何 Mongo bean 实例化问题的情况下使用 Java 8 和 Spring Data MongoDb Reactive 的 Java maven 项目。目前,我正在尝试将同一个项目从 Java 8 项目升级到 Java 11 (jvm 11.0.8+10-LTS)。我更新的 Spring Boot 版本是 2.5.6,带有 Jetty 服务器(9.4.44.v20210927),对应的 Mongo 响应式版本是基于 2.5.6。当 Spring 尝试创建与 mongo 相关的 bean 以将它们添加到上下文中时,会出现以下错误:

Unable to support mongodb+srv// style connections as the ‘com.sun.jndi.dns.DnsContextFactory’ "
+ "class is not available in this JRE. A JNDI context is required for resolving SRV records

我尝试过以下方法:

添加设置属性的 jndi.properties 文件

java.naming.provider.url=dns:.

在 maven 编译器插件中添加 -exports 参数

 <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                        <release>11</release>
                    <compilerArgs>
                        <arg>--add-exports</arg>
                        <arg>jdk.naming.dns/com.sun.jndi.dns=java.naming</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>

升级到兼容 java 11 的最新 jetty server 版本

 <jetty.version>9.4.44.v20210927</jetty.version>

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-webapp</artifactId>
 <version>$jetty.version</version>
 <scope>provided</scope>
  </dependency>

你能告诉我一个解决方案吗?

【问题讨论】:

【参考方案1】:

我认为您实际上不必添加--add-exports。如果您查看 Mongodb Java 驱动程序代码,您会发现它已经添加了dns:

这是一个 PR https://github.com/mongodb/mongo-java-driver/pull/554

这可能与 JVM 有关,但很难证明这一点。您可以使用 OpenJDK 11 在 docker 容器上运行它并查看吗?还是不同的版本?

    /*
      It's unfortunate that we take a runtime dependency on com.sun.jndi.dns.DnsContextFactory.
      This is not guaranteed to work on all JVMs but in practice is expected to work on most.
    */
    private static InitialDirContext createDnsDirContext() 
        Hashtable<String, String> envProps = new Hashtable<String, String>();
        envProps.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
        envProps.put(Context.PROVIDER_URL, "dns:");
        try 
            return new InitialDirContext(envProps);
         catch (NamingException e) 
            throw new MongoClientException("Unable to support mongodb+srv// style connections as the 'com.sun.jndi.dns.DnsContextFactory' "
                    + "class is not available in this JRE. A JNDI context is required for resolving SRV records.", e);
        
    

https://github.com/mongodb/mongo-java-driver/blob/master/driver-core/src/main/com/mongodb/internal/dns/DefaultDnsResolver.java

【讨论】:

我尝试使用 URI 的 DNS 样式表示法创建一个具有相同 Java 版本 (11) 和 mongo 依赖项的小项目,它可以正常工作。问题可能出在依赖项或其他地方。 @SocketM 最后,您可以为响应式 mongo 添加最新的驱动程序,看看是否能解决您的问题...否则,如果没有,则不要使用 SRV。 https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-reactivestreams/4.4.0 我试过了。我使用了 spring boot 最新版本,它还汇集了最新版本的 mongo db reactive。通常我使用 srv 表示法,因为我可以使用 DNS 服务器,并且我从 txt 中提取了一些配置。缺点是我必须对包括生产在内的所有主机和端口进行硬编码,而不是使用 DNS。

以上是关于使用 DNS 记录(SRV 和 TXT)时,无法在 Spring 上下文中实例化 Mongo 相关 bean的主要内容,如果未能解决你的问题,请参考以下文章

如何在golang的k8s集群dns中查找SRV记录

如何使用 Strophe JS 获取 DNS SRV 记录?

sh shell函数用于爬网dns树并在每个父区域中搜索SRV记录。一旦找到第一个SRV记录,它将退出。

使用领事的SRV记录

中科三方DNS云解析产品常见问答

DevOps之域名