Java 中文官方教程 2022 版(四十八)(3)

简介: Java 中文官方教程 2022 版(四十八)

Java 中文官方教程 2022 版(四十八)(2)https://developer.aliyun.com/article/1488516

类似地,当上下文方法从 list()、listBindings() 或 search() 操作返回结果时,可以通过调用getNameInNamespace()检索 DN。可以直接从 DN 构造 LdapName,如示例中所示,RetrievingLdapName

while (answer.hasMore()) {
    SearchResult sr = (SearchResult) answer.next();
    String name = sr.getNameInNamespace();
    System.out.println(name);
    LdapName dn = new LdapName(name);
    // do something with the dn

操作相对独立名称(RDN)

原文:docs.oracle.com/javase/tutorial/jndi/newstuff/rdn.html

javax.naming.ldap.Rdn表示根据RFC 2253指定的相对独立名称(RDN)。RDN 表示 DN 的组件,如操作 LdapName 课程中所解释的那样。RDN 由类型和值对组成。RDN 的示例包括:

  • OU=Sun
  • OU=Sales+CN=J.Smith
    上面的示例显示了多值 RDN 的表示。

Rdn类提供了访问 RDN 的名称/值对、获取其字符串表示、检索Attributes视图、比较和确定 RDN 的相等性以及转义和取消转义 RDN 值部分的方法。

Rdn类是不可变的。

构造 Rdn

如果是单个名称/值对的 RDN,可以使用指定的名称和值对构造 Rdn。对于多值 RDN,应创建包含所有名称/值对的属性集,并使用以Attributes为参数的构造函数。还可以根据RFC 2253中指定的字符串表示创建 Rdn。最后,可以使用其复制构造函数克隆 Rdn。这里是一个使用不同类型构造函数创建 RDN 的示例

Rdn rdn1 = new Rdn("ou= Juicy\\, Fruit");
        System.out.println("rdn1:" + rdn1.toString());
        Rdn rdn2 = new Rdn(rdn1);
        System.out.println("rdn2:" + rdn2.toString());
        Attributes attrs = new BasicAttributes();
        attrs.put("ou", "Juicy, Fruit");
        attrs.put("cn", "Mango");
        Rdn rdn3 = new Rdn(attrs);
        System.out.println("rdn3:" + rdn3.toString());
        Rdn rdn4 = new Rdn("ou", "Juicy, Fruit");
        System.out.println("rdn4:" + rdn4.toString());

访问 RDN 的类型/值对

可以使用以下方法获取 RDN 的类型/值:

getType()

getValue()

toAttributes()

对于由单个类型/值对组成的 RDN,getType()方法返回类型,getValue()方法返回 RDN 的值。方法toAttributes()返回类型/值对的属性视图。下面的示例打印了 RDN 的类型/值对。

Attributes attrs = new BasicAttributes();
        attrs.put("o", "Yellow");
        attrs.put("cn", "Mango");
        // create a binary value for the RDN
        byte[] mangoJuice = new byte[6];
        for (int i = 0; i < mangoJuice.length; i++) {
            mangoJuice[i] = (byte) i;
        }
        attrs.put("ou", mangoJuice);
        Rdn rdn = new Rdn(attrs);
        System.out.println();
        System.out.println("size:" + rdn.size());
        System.out.println("getType(): " + rdn.getType());
        System.out.println("getValue(): " + rdn.getValue());
        // test toAttributes
        System.out.println();
        System.out.println("toAttributes(): " + rdn.toAttributes());

获取字符串表示

为了按照RFC 2253中指定的语法格式化 RDN 的字符串表示,可以使用:

toString()

当您使用接受String参数的 Rdn 构造函数时,您提供了 RDN 的字符串表示,并获得了一个 Rdn 实例。要做相反的操作,即获取 Rdn 实例的字符串表示,您可以使用 toString()。toString()的结果可以馈送回 Rdn 构造函数,以产生与原始 Rdn 实例相等的 Rdn 实例。

这里有一个示例

Rdn rdn = new Rdn("cn=Juicy\\,Fruit");
String str = rdn.toString();
System.out.println(str);
Rdn rdn2 = new Rdn(str);
System.out.println(rdn.equals(rdn2));    // true

比较 RDNs

下面的方法使 RDN 的比较成为可能:

equals(Object Rdn)

compareTo(Object Rdn)

您可以使用 compareTo()对 Rdn 实例列表进行排序。equals()让您确定两个 Rdns 在语法上是否相等。如果两个 Rdns 都具有相同(大小写匹配)的类型/值对,则它们是相等的。多值 RDN 中组件的顺序不重要。

这里有一个示例

Rdn one = new Rdn("ou=Sales+cn=Bob");
        Rdn two = new Rdn("cn=Bob+ou=Sales");
        Rdn three = new Rdn("ou=Sales+cn=Bob+c=US");
        Rdn four = new Rdn("cn=lowercase");
        Rdn five = new Rdn("cn=LowerCASE");
        System.out.println(one.equals(two));    // true
        System.out.println(two.equals(three));  // false
        System.out.println(one.equals(three));  // false
        System.out.println(four.equals(five));  // true

转义和反转义特殊字符

Rdn 类的最佳用途之一是处理包含特殊字符的 DN。它会自动处理特殊字符的转义和反转义。像 ‘’(反斜杠)、‘,’(逗号)、+(加号)等字符在RFC 2253中有特定的语义。您可以在 RFC2253 中找到所有特殊字符的列表。当这些字符作为 DN 中的文字时,必须用 ‘’(反斜杠)进行转义。

例如,考虑一个 RDN:cn=Juicy, Fruit,出现在 Juicy 和 Fruit 之间的逗号,是一个需要用 ‘’(反斜杠)转义的特殊字符。经过语法格式化后的 RDN 如下所示:cn=Juicy\, Fruit 然而, ‘’(反斜杠)字符本身是 Java 语言字符串语法中的一个特殊字符,需要再次用 ‘’(反斜杠)转义。Java 语言字符串格式和RFC 2253都使用 ‘’(反斜杠)来转义特殊字符。因此,Java 格式化的 RDN 字符串如下所示:cn=Juicy\\, Fruit 请注意,上述提到的格式化规则仅适用于 Rdn 的值组件。Rdn类提供了两个static方法来处理 RDN 值的自动转义和反转义:

escapeValue()

unescapeValue()

下面的示例显示了如何获取 DN 的字符串表示,而无需处理RFC 2253中定义的处理特殊字符的语法。

// DN with ',' (comma)
    String unformatted = "Juicy, Fruit";
    String formatted = Rdn.escapeValue(unformatted);
    LdapName dn = new LdapName("cn=" + formatted);
    System.out.println("dn:" + dn);
    unformatted = "true+false";
    formatted = Rdn.escapeValue(unformatted); 
    dn = new LdapName("cn=" + formatted);
    System.out.println("dn:" + dn);
    // DN with a binary value as one of its attribute values
    byte[] bytes = new byte[] {1, 2, 3, 4};
    formatted = Rdn.escapeValue(bytes);
    System.out.println("Orig val: " + bytes + "Escaped val: " + formatted);

同样地,使用静态的unescapeValue()方法,可以从格式化值中获取原始字符串。这里是一个检索原始值的示例。

// DN with ',' (comma)
    String unformatted = "Juicy, Fruit";
    String formatted = Rdn.escapeValue(unformatted);
    System.out.println("Formatted:" + formatted);
    Object original = Rdn.unescapeValue(formatted);
    System.out.println("Original:" +  original);  
    // DN with a '+' (plus)
    unformatted = "true+false";
    formatted = Rdn.escapeValue(unformatted); 
    System.out.println("Formatted:" + formatted);
    original = Rdn.unescapeValue(formatted);
    System.out.println("Original:" +  original);  
    // DN with a binary value as one of its attribute values
    byte[] bytes = new byte[] {1, 2, 3, 4};
    formatted = Rdn.escapeValue(bytes);
    System.out.println("Formatted:" + formatted);
    original = Rdn.unescapeValue(formatted);
    System.out.println("Original:" +  original);  

设置 LDAP 操作的超时时间

原文:docs.oracle.com/javase/tutorial/jndi/newstuff/readtimeout.html

当客户端向服务器发出 LDAP 请求并且服务器由于某种原因未响应时,客户端将永远等待服务器响应,直到 TCP 超时。在客户端端,用户体验实际上是一个进程挂起。为了及时控制 LDAP 请求,自 Java SE 6 以来可以为 JNDI/LDAP 服务提供程序配置读取超时。

新的环境属性:

com.sun.jndi.ldap.read.timeout

可用于指定 LDAP 操作的读取超时时间。该属性的值是表示 LDAP 操作的读取超时时间(以毫秒为单位)的整数的字符串表示。如果 LDAP 提供程序在指定的时间内未收到 LDAP 响应,则会中止读取尝试。整数应大于零。小于或等于零的整数表示未指定读取超时,相当于无限等待响应直到接收到响应,这是默认行为。

如果未指定此属性,默认情况下将等待响应直到接收到响应。

例如,env.put("com.sun.jndi.ldap.read.timeout", "5000"); 会导致 LDAP 服务提供程序在服务器在 5 秒内未响应时中止读取尝试。

这里有一个示例,ReadTimeoutTest,使用一个不响应 LDAP 请求的虚拟服务器,展示了当将此属性设置为非零值时的行为。

env.put(Context.INITIAL_CONTEXT_FACTORY,
        "com.sun.jndi.ldap.LdapCtxFactory");
env.put("com.sun.jndi.ldap.read.timeout", "1000");
env.put(Context.PROVIDER_URL, "ldap://localhost:2001");
Server s = new Server();
try {
    // start the server
    s.start();
   // Create initial context
   DirContext ctx = new InitialDirContext(env);
   System.out.println("LDAP Client: Connected to the Server");
        :
        :
} catch (NamingException e) {
   e.printStackTrace();
}

由于服务器甚至未响应 LDAP 绑定请求,当创建 InitialDirContext 时,上述程序打印下面的堆栈跟踪。客户端在等待服务器响应时超时。

Server: Connection accepted
javax.naming.NamingException: LDAP response read timed out, timeout used:1000ms.
:
:
at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:82)
at ReadTimeoutTest.main(ReadTimeoutTest.java:32)

请注意,此属性与另一个环境属性 com.sun.jndi.ldap.connect.timeout 不同,后者设置连接到服务器的超时时间。读取超时适用于与服务器建立初始连接后从服务器接收的 LDAP 响应。

Trail: Sockets Direct Protocol

原文:docs.oracle.com/javase/tutorial/sdp/index.html

Sockets Direct Protocol(SDP)提供了对高性能网络连接的访问,例如 InfiniBand 提供的连接。本教程展示了如何启用 SDP,涉及哪些 Java API,并解释了它的工作原理。

课程:理解套接字直接协议

原文:docs.oracle.com/javase/tutorial/sdp/sockets/index.html

对于高性能计算环境,快速高效地在网络中传输数据是必需的。这样的网络通常被描述为需要高吞吐量和低延迟。高吞吐量指的是在长时间内可以提供大量处理能力的环境。低延迟指的是处理输入并提供输出之间的最小延迟,就像您在实时应用程序中所期望的那样。

在这些环境中,使用套接字流进行传输数据可能会导致瓶颈。InfiniBand(IB)由InfiniBand 贸易协会于 1999 年推出,旨在满足高性能计算的需求。IB 的最重要特性之一是远程直接内存访问(RDMA)。RDMA 使得可以直接从一台计算机的内存移动数据到另一台计算机,绕过两台计算机的操作系统,从而实现显著的性能提升。

套接字直接协议(SDP)是一种网络协议,旨在支持在 InfiniBand 结构上的流连接。SDP 支持是在 Java 平台标准版(“Java SE 平台”)的 JDK 7 版本中引入的,用于在 Solaris 操作系统(“Solaris OS”)和 Linux 操作系统上部署的应用程序。Solaris OS 自 Solaris 10 5/08 版本以来一直支持 SDP 和 InfiniBand。在 Linux 上,InfiniBand 软件包称为 OFED(OpenFabrics 企业发行版)。JDK 7 版本支持 OFED 的 1.4.2 和 1.5 版本。

概述

原文:docs.oracle.com/javase/tutorial/sdp/sockets/overview.html

SDP 支持本质上是一种 TCP 绕过技术。

当启用 SDP 并且应用程序尝试打开 TCP 连接时,TCP 机制将被绕过,通信直接传输到 IB 网络。例如,当您的应用程序尝试绑定到 TCP 地址时,基础软件将根据配置文件中的信息决定是否应重新绑定到 SDP 协议。此过程可以在绑定过程或连接过程中发生(但每个套接字仅发生一次)。

在您的代码中利用 SDP 协议无需进行 API 更改:实现是透明的,并受经典网络(java.net)和新 I/O(java.nio.channels)包的支持。查看支持的 Java API 部分,了解支持 SDP 协议的类列表。

SDP 支持默认情况下是禁用的。启用 SDP 支持的步骤如下:

  • 创建一个 SDP 配置文件。
  • 设置指定配置文件位置的系统属性。

创建一个 SDP 配置文件

原文:docs.oracle.com/javase/tutorial/sdp/sockets/file.html

一个 SDP 配置文件是一个文本文件,您可以决定这个文件将存放在文件系统的哪个位置。配置文件中的每一行都是一个注释或一个规则。注释以井号字符(#)开头,井号字符后的所有内容将被忽略。

有两种类型的规则,如下:

  • "bind"规则表示当 TCP 套接字绑定到与规则匹配的地址和端口时,应使用 SDP 协议传输。
  • "connect"规则表示当未绑定的 TCP 套接字尝试连接到与规则匹配的地址和端口时,应使用 SDP 协议传输。

一个规则的形式如下:

("bind"|"connect")1*LWSP-char(hostname|ipaddress)["/"prefix])1*LWSP-char("*"|port)["-"("*"|port)]

解码符号:

1LWSP-char表示任意数量的线性空白字符(制表符或空格)可以分隔标记。方括号表示可选文本。符号(xxx | yyy)表示标记将包括xxxyyy*中的一个,但不会同时包括两者。引号中的字符表示文字。


第一个关键字指示规则是bind还是connect规则。下一个标记指定主机名或文字 IP 地址。当指定文字 IP 地址时,您还可以指定前缀,表示 IP 地址范围。第三个也是最后一个标记是端口号或端口号范围。

在这个示例配置文件中考虑以下符号:

# Use SDP when binding to 192.0.2.1
bind 192.0.2.1 *
# Use SDP when connecting to all application services on 192.0.2.*
connect 192.0.2.0/24     1024-*
# Use SDP when connecting to the http server or a database on examplecluster
connect examplecluster.example.com   80
connect examplecluster.example.com   3306

示例文件中的第一条规则指定 SDP 用于本地 IP 地址192.0.2.1上的任何端口(*)。对于每个分配给 InfiniBand 适配器的本地地址,您将添加一个绑定规则。(InfiniBand 适配器相当于 InfiniBand 的网络接口卡(NIC)。)如果您有多个 IB 适配器,您将为分配给这些适配器的每个地址使用一个绑定规则。

示例文件中的第二条规则指定每当连接到192.0.2.*并且目标端口大于或等于 1024 时,将使用 SDP。IP 地址前缀/24表示 32 位 IP 地址的前 24 位应与指定地址匹配。IP 地址的每个部分使用 8 位,因此 24 位表示 IP 地址应匹配192.0.2,最后一个字节可以是任何值。端口标记上的-*符号指定“及以上”。端口范围,例如 1024—2056,也是有效的,并且将包括指定范围的端点。

示例文件中的最后规则指定一个主机名(examplecluster),首先分配给 http 服务器的端口(80),然后分配给数据库的端口(3306)。与文字 IP 地址不同,主机名可以转换为多个地址。当指定主机名时,它匹配主机名在名称服务中注册的所有地址。

启用 SDP 协议

原文:docs.oracle.com/javase/tutorial/sdp/sockets/enable.html

SDP 支持默认情况下是禁用的。要启用 SDP 支持,请设置com.sun.sdp.conf系统属性,提供配置文件的位置。以下示例启动一个使用名为sdp.conf的配置文件的应用程序:

% java -Dcom.sun.sdp.conf=sdp.conf -Djava.net.preferIPv4Stack=true  *ExampleApplication*

ExampleApplication指的是试图连接到 IB 适配器的客户端应用程序。

请注意,此示例指定另一个系统属性java.net.preferIPv4Stack。有关为什么使用此属性的更多信息,请参见 Issues 部分。

调试 SDP

原文:docs.oracle.com/javase/tutorial/sdp/sockets/debug.html

你可以通过使用-Dcom.sun.sdp.debug标志来启用调试消息。如果你指定一个文件,消息将被输出到该文件。否则,消息将被打印到标准输出。

这个第一个示例展示了打印到标准输出的示例消息:

% java -Dcom.sun.sdp.conf=sdp.conf -Dcom.sun.sdp.debug *ExampleApplicaton*
BIND to 192.0.2.1:5000 (socket converted to SDP protocol)
CONNECT to 129.156.232.160:80 (no match)
CONNECT to 192.0.2.2:80 (socket converted to SDP protocol)

这个第二个示例展示了输出重定向到名为debug.log的文件:

% java -Dcom.sun.sdp.conf=sdp.conf -Dcom.sun.sdp.debug=debug.log *ExampleApplication* 
[1] 27310
% tail -f debug.log
BIND to 192.0.2.1:5000 (socket converted to SDP protocol)

SDP 的技术问题

原文:docs.oracle.com/javase/tutorial/sdp/sockets/issues.html

  • IPv4 和 IPv6 不兼容
    互联网协议第 4 版(IPv4)长期以来一直是 Internet 协议(IP)的行业标准版本,用于在 Internet 上传输数据。互联网协议第 6 版(IPv6)是下一代 Internet 层协议。今天仍在使用这两个版本的 IP。
    IPv4 地址是 32 位长,以十进制格式编写,并用句点分隔。IPv6 地址是 128 位长,以十六进制格式编写,并用冒号分隔。IPv4 地址不能直接在 IPv6 中使用,但 IPv6 支持一种特殊类别的地址:IPv4 映射地址。在 IPv4 映射地址中,前 80 位设置为零,接下来的 16 位设置为 1,最后 32 位表示 IPv4 地址。
    例如,这里是相同的 IP 地址以两种格式表示:
IPv4 address                  IPv4-mapped address (for use in IPv6)
192.0.2.1                   ::ffff:192.0.2.1
  • 默认情况下,如果 IB 适配器中启用了 IPv6,则 Java 平台将使用 IPv6。然而,在 Solaris 操作系统或 Linux 下目前不支持 IPv4 映射地址。因此,如果您想在 JDK 7 下使用 IPv4 地址格式,必须指定java.net.preferIPv4Stack属性,如下例所示:
% java -Dcom.sun.sdp.conf=sdp.conf -Djava.net.preferIPv4Stack=true  *MyApplication*
  • 错误
    在早期 InfiniBand 实现中发现了一些错误。这些错误在 Solaris 10 10/09 版本中已修复。请确保您至少使用此版本。

Solaris 和 Linux 支持

原文:docs.oracle.com/javase/tutorial/sdp/sockets/support.html

Solaris 10

要测试 SDP 是否已启用,请使用sdpadm(1M)命令:

% /usr/sbin/sdpadm status
SDP is Enabled

你可以使用 grep 命令在/etc/path_to_inst文件中搜索字符串"ibd",以查看网络上支持的 IB 适配器列表。

其他你可能会发现有用的命令包括ib(7D)、ibd(7D)和sdp(7D)。

Solaris 11

你可以使用以下命令获取 InfiniBand 分区链接信息:

% dladm show-port -o LINK

其他你可能会发现有用的命令包括ib(7D)、ibd(7D)和sdp(7D)。

Linux

你可以使用以下命令获取 InfiniBand 适配器的列表:

% egrep "^[ \t]+ib" /proc/net/dev

支持的 Java API

原文:docs.oracle.com/javase/tutorial/sdp/sockets/supported.html

所有使用 TCP 的 API 都可以使用 SDP,特别包括以下类:

  • java.net
  • Socket
  • ServerSocket
  • java.nio.channels包:
  • SocketChannel
  • ServerSocketChannel
  • AsynchronousSocketChannel
  • AsynchronousServerSocketChannel

当启用 SDP 支持时,它会在不需要对您的代码进行任何更改的情况下正常工作。不需要编译。然而,重要的是要知道套接字只绑定一次。连接是隐式绑定。因此,如果套接字之前没有绑定并且调用了 connect,则绑定将在那个时候发生。

例如,考虑以下代码片段:

AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
ch.bind(local);
Future<Void> result = ch.connect(remote);

在此代码片段中,当在套接字上调用 bind 时,异步套接字通道将绑定到本地 TCP 地址。然后,代码尝试使用相同的套接字连接到远程地址。如果远程地址使用配置文件中指定的 InfiniBand,则连接不会转换为 SDP,因为套接字先前已绑定。

更多信息请参考

原文:docs.oracle.com/javase/tutorial/sdp/sockets/info.html

教程:Java Architecture for XML Binding

原文:docs.oracle.com/javase/tutorial/jaxb/index.html

Java Architecture for XML Binding (JAXB) 教程介绍了 Java Architecture for XML Binding (JAXB) 技术,通过 JAXB 应用示例。

在阅读本教程之前

要理解并使用 Java Architecture for XML Binding (JAXB) 教程中的信息,您应该具备以下技术知识:

  • Java 编程语言及其开发环境
  • 可扩展标记语言(XML)

本教程详细讨论了仅与 JAXB 相关的代码。

简要描述了 JAXB 技术,包括其目的和主要特点。

Java 中文官方教程 2022 版(四十八)(4)https://developer.aliyun.com/article/1488524

相关文章
|
23天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
3月前
|
Java 开发者 UED
【实战宝典】Java异常处理大师级教程:throws关键字,让异常声明成为你的专属标签!
【实战宝典】Java异常处理大师级教程:throws关键字,让异常声明成为你的专属标签!
54 3
|
1天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
1天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
1天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
|
10天前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
24 2
|
17天前
|
Java 数据库连接 编译器
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
|
20天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
本系列教程笔记详细讲解了Kotlin语法,适合希望深入了解Kotlin的开发者。对于需要快速学习Kotlin的小伙伴,推荐查看“简洁”系列教程。本篇笔记重点介绍了Kotlin与Java混编的技巧,包括代码转换、类调用、ProGuard问题、Android库开发建议以及相互调用时的注意事项。
21 3
|
22天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
20 3
|
23天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)