# 创建

> 原文： [https://docs.oracle.com/javase/tutorial/jndi/ldap/create.html](https://docs.oracle.com/javase/tutorial/jndi/ldap/create.html)

有几种方法可以创建连接。最常见的方式是创建初始上下文。使用 LDAP 创建 [`InitialContext`](https://docs.oracle.com/javase/8/docs/api/javax/naming/InitialContext.html)， [`InitialDirContext`](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/InitialDirContext.html)或 [`InitialLdapContext`](https://docs.oracle.com/javase/8/docs/api/javax/naming/ldap/InitialLdapContext.html)服务提供程序，立即使用 [`Context.PROVIDER_URL`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#PROVIDER_URL)属性中指定的目标 LDAP 服务器建立连接。每次创建初始上下文时，都会创建一个新的 LDAP 连接。有关如何更改此行为的信息，请参阅 [Pooling](pool.html) 部分。

如果属性值包含多个 URL，则依次尝试每个 URL，直到使用一个 URL 来创建成功的连接。然后将属性值更新为成功的 URL。有关如何使用 URL 列表创建初始上下文的示例，请参阅 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/ldap/misc/url.html#MULTI)。

还有其他三种直接创建连接的方式。

1.  通过将 URL 作为 name 参数传递给初始上下文。将 LDAP 或 LDAPS URL 作为名称参数传递给初始上下文时，无论初始上下文实例本身是否与 LDAP 服务器建立连接，URL 中的信息都将用于创建与 LDAP 服务器的新连接。实际上，初始上下文可能未连接到任何服务器。有关如何将 URL 用作名称的详细信息，请参阅 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/beyond/url/initctx.html)。
2.  创建连接的另一种方法是使用 `Reference` 。当包含 LDAP 或 LDAPS URL 的 [`参考`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Reference.html) 传递给 [`NamingManager.getObjectInstance（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/spi/NamingManager.html#getObjectInstance-java.lang.Object-javax.naming.Name-javax.naming.Context-java.util.Hashtable-) 或 [`DirectoryManager 时。 getObjectInstance（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/spi/DirectoryManager.html#getObjectInstance-java.lang.Object-javax.naming.Name-javax.naming.Context-java.util.Hashtable-javax.naming.directory.Attributes-) ，使用 URL 中指定的信息创建新连接。
3.  最后，当手动或自动跟踪引荐时，引用中的信息用于创建新连接。有关推荐的信息，请参阅 [JNDI 教程](https://docs.oracle.com/javase/jndi/tutorial/ldap/referral/index.html)。

## 共享连接

`派生自`上下文`实例的上下文`实例和 [`NamingEnumeration` s](https://docs.oracle.com/javase/8/docs/api/javax/naming/NamingEnumeration.html) 共享相同的连接，直到更改为`上下文之一`实例使得共享不再可能。例如，如果你调用 [`Context.lookup（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#lookup-javax.naming.Name-) ， [`Context.listBindings（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/Context.html#listBindings-javax.naming.Name-) 或 [`DirContext。搜索（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/directory/DirContext.html#search-javax.naming.Name-java.lang.String-javax.naming.directory.SearchControls-) 从初始上下文中获取其他 `Context` 实例，然后所有这些 `Context` 实例将共享相同的连接。

这是 [`an example`](examples/Shared.java) 。

```
// Create initial context
DirContext ctx = new InitialDirContext(env);

// Get a copy of the same context
Context ctx2 = (Context)ctx.lookup("");

// Get a child context
Context ctx3 = (Context) ctx.lookup("ou=NewHires");

```

在该示例中， `ctx` ， `ctx2` 和 `ctx3` 将共享相同的连接。

无论 `Context` 实例如何存在，共享都会完成。例如，通过跟随推荐获得的`上下文`实例将与推荐共享相同的连接。

当您更改 `Context` 实例的与连接相关的环境属性（例如用户的主体名称或凭据）时，您进行这些更改的 `Context` 实例将获得其自己的连接（如果共享连接）。 `将来从此 `Context` 实例派生的 Context` 实例将共享此新连接。 `先前共享旧连接的上下文`实例不受影响（即，它们继续使用旧连接）。

这是使用两个连接的 [`an example`](examples/NewConn.java) 。

```
// Create initial context (first connection)
DirContext ctx = new InitialDirContext(env);

// Get a copy of the same context
DirContext ctx2 = (DirContext)ctx.lookup("");

// Change authentication properties in ctx2
ctx2.addToEnvironment(Context.SECURITY_PRINCIPAL, 
    "cn=C. User, ou=NewHires, o=JNDITutorial");
ctx2.addToEnvironment(Context.SECURITY_CREDENTIALS, "mysecret");

// Method on ctx2 will use new connection
System.out.println(ctx2.getAttributes("ou=NewHires"));

```

`ctx2` 最初与 `ctx` 共享相同的连接。但是当它的主要和密码属性改变时，它就不能再使用 `ctx` 的连接了。 LDAP 提供程序将自动为 `ctx2` 创建新连接。

同样，如果你使用 [`LdapContext.reconnect（）`](https://docs.oracle.com/javase/8/docs/api/javax/naming/ldap/LdapContext.html#reconnect-javax.naming.ldap.Control:A-) 更改 `Context` 实例的连接控件， `Context` 实例将获得自己的连接如果连接正在共享。

如果 `Context` 实例的连接没有被共享（即，没有从它派生 `Context` ），那么对其环境或连接控件的更改将不会导致新连接创建。相反，任何与连接相关的更改都将应用于现有连接。

并非所有连接创建都是成功的。如果 LDAP 提供程序无法在某个超时期限内建立连接，则会中止连接尝试。默认情况下，此超时时间是网络（TCP）超时值，大约为几分钟。要更改超时时间，请使用`“com.sun.jndi.ldap.connect.timeout”`环境属性。此属性的值是表示连接超时的整数的字符串表示形式（以毫秒为单位）。

这是 [`an example`](examples/Timeout.java) 。

```
// Set up environment for creating initial context
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, 
    "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");

// Specify timeout to be 5 seconds
env.put("com.sun.jndi.ldap.connect.timeout", "5000");

// Create initial context
DirContext ctx = new InitialDirContext(env);

// do something useful with ctx

```

在此示例中，如果无法在 5 秒内创建连接，则将引发异常。

如果 `Context.PROVIDER_URL` 属性包含多个 URL，则提供程序将使用每个 URL 的超时。例如，如果有 3 个 URL 并且超时已指定为 5 秒，则提供程序将总共等待最多 15 秒。

有关此属性如何影响连接池的信息，请参见[连接池](pool.html#TIMEOUT)部分。