一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java中的命名與目錄接口JNDI基本操作方法概覽

Java中的命名與目錄接口JNDI基本操作方法概覽

2020-04-14 11:29kyfxbl JAVA教程

這篇文章主要介紹了Java中的命名與目錄接口JNDI基本操作方法概覽,JNDI提供統一的客戶端API使得Java應用程序可以和這些命名服務和目錄服務之間進行交互,需要的朋友可以參考下

對jndi總體的理解:

jndi(java naming and directory Interface)它提供了一套使用命名和目錄服務的接口。用戶可以通過它來使用命名和目錄服務。就像jdbc一樣。jndi包括命名服務和目錄服務兩部分,其中目錄服務包含目錄對象directory object,它包含若干屬性對象。提供了對屬性的很多操作。
命名和目錄服務:

命名和目錄服務我們一直在使用,如操作系統的文件系統,它給我們提供對文件的操作,查詢,添加刪除等功能。DNS服務將url同ip地址綁定在了一起。命名和目錄系統的最主要的功能是將name和對象綁定。在它的基礎之上還提供更多的功能如lookup,search.而且存儲的對象是有一定層次結構的。使用這樣的服務我們可以對對象更加有效的管理和操作。
命名服務將一個名稱映射到一個對象。RMI Registry和CORBA Naming Service都是命名服務。
目錄服務也存放對象,但目錄服務識別這些對象的相關屬性。可以用項目屬性來搜索目錄。
在20世紀90年代早期,輕量級的目錄訪問協議(LightWeightDiretoryAccessProtocol,LDAP)被作為一種標準的目錄協議被開發出來,JNDI能夠訪問LDAP。
j2se為jndi提供了5個擴展包:

  • javax.naming;為訪問命名服務提供的api
  • javax.naming.directory;為訪問目錄服務提供了基本的接口
  • javax.naming.event;支持命名和目錄服務中的事件通知
  • javax.naming.ldap; 支持ldap的包,
  • javax.naming.spi;提供了不同命名和目錄服務可以掛接他們的實現的方法。

context: context是一套name-to-object的綁定(bindings),可以理解為層次或目錄,它還可已包括下一層subContext。在使用命名和目錄服務時獲得initial context是對整個名字空間操作的入口。在目錄服務中是DirContext.
JNDI(Java Naming and Directory Interface)是一個應用程序設計的API,為開發人員提供了查找和訪問各種命名和目錄服務的通用、統一的接口,類似JDBC都是構建在抽象層上。
JNDI可訪問的現有的目錄及服務有:
DNS、XNam 、Novell目錄服務、LDAP(Lightweight Directory Access Protocol 輕型目錄訪問協議)、 CORBA對象服務、文件系統、Windows XP/2000/NT/Me/9x的注冊表、RMI、DSML v1&v2、NIS。
JNDI優點:
包含了大量的命名和目錄服務,使用通用接口來訪問不同種類的服務;可以同時連接到多個命名或目錄服務上;建立起邏輯關聯,允許把名稱同Java對象或資源關聯起來,而不必指導對象或資源的物理ID。

JNDI程序包:

  • javax.naming:命名操作;
  • javax.naming.directory:目錄操作;
  • javax.naming.event:在命名目錄服務器中請求事件通知;
  • javax.naming.ldap:提供LDAP支持;
  • javax.naming.spi:允許動態插入不同實現。
  • 利用JNDI的命名與服務功能來滿足企業級APIs對命名與服務的訪問,諸如EJBs、JMS、JDBC 2.0以及IIOP上的RMI通過JNDI來使用CORBA的命名服務。

JNDI與JDBC:
JNDI提供了一種統一的方式,可以用在網絡上查找和訪問服務。通過指定一個資源名稱,該名稱對應于數據庫或命名服務中的一個紀錄,同時返回數據庫連接建立所必須的信息。
代碼示例:

?
1
2
3
4
5
6
7
try{
Context cntxt = new InitialContext();
DataSource ds = (DataSource) cntxt.lookup("jdbc/dpt");
}
catch(NamingException ne){
...
}

JNDI與JMS:
消息通信是軟件組件或應用程序用來通信的一種方法。JMS就是一種允許應用程序創建、發送、接收、和讀取消息的JAVA技術。
代碼示例:

?
1
2
3
4
5
6
7
8
9
try{
Properties env = new Properties();
InitialContext inictxt = new InitialContext(env);
TopicConnectionFactory connFactory = (TopicConnectionFactory) inictxt.lookup("TTopicConnectionFactory");
...
}
catch(NamingException ne){
...
}

訪問特定目錄:舉個例子,人是個對象,他有好幾個屬性,諸如這個人的姓名、電話號碼、電子郵件地址、郵政編碼等屬性。通過getAttributes()方法

?
1
2
Attribute attr = directory.getAttributes(personName).get("email");
String email = (String)attr.get();

通過使用JNDI讓客戶使用對象的名稱或屬性來查找對象:

?
1
foxes = directory.search("o=Wiz,c=US", "sn=Fox", controls);

通過使用JNDI來查找諸如打印機、數據庫這樣的對象,查找打印機的例子:

?
1
2
Printer printer = (Printer)namespace.lookup(printerName);
printer.print(document);

瀏覽命名空間:

?
1
2
3
4
5
NamingEnumeration list = namespace.list("o=Widget, c=US");
while (list.hasMore()) {
NameClassPair entry = (NameClassPair)list.next();
display(entry.getName(), entry.getClassName());
}
  • 常用的JNDI操作:
  • void bind(String sName,Object object);――綁定:把名稱同對象關聯的過程
  • void rebind(String sName,Object object);――重新綁定:用來把對象同一個已經存在的名稱重新綁定
  • void unbind(String sName);――釋放:用來把對象從目錄中釋放出來
  • void lookup(String sName,Object object);――查找:返回目錄總的一個對象
  • void rename(String sOldName,String sNewName);――重命名:用來修改對象名稱綁定的名稱
  • NamingEnumeration listBinding(String sName);――清單:返回綁定在特定上下文中對象的清單列表
  • NamingEnumeration list(String sName);

代碼示例:重新得到了名稱、類名和綁定對象。

?
1
2
3
4
5
6
7
8
NamingEnumeration namEnumList = ctxt.listBinding("cntxtName");
...
while ( namEnumList.hasMore() ) {
Binding bnd = (Binding) namEnumList.next();
String sObjName = bnd.getName();
String sClassName = bnd.getClassName();
SomeObject objLocal = (SomeObject) bnd.getObject();
}

 

了解名字服務和目錄服務的相關概念,有助于更好的使用JNDI。 Naming service       名字服務定義了如何將名字與對象關聯,并通過名字如何找到對象的方法。典型的例子如:DNS將域名與IP關聯,文件系統將文件名與文件相關聯。在名字服務中,主要的概念:
-          名字(Names),在名字系統中實際對象的代號,如文件名,域名等,它會被用來查找關聯的對象。不同的系統中會有不同的命名規范,如文件系統采用“\”來表示層級,而DNS則使用“.”。
-          綁定(Bindings),名字和實際對象的關聯。
-          引用和地址(References and Addresses),當對象不能直接被存儲在名字系統時,就必須使用引用,通過引用找到實際的對象。在系統中,保存的引用的內容被稱為地址。引用還有另一個用處:在名字系統中,缺少象關系數據庫中外鍵的概念。通過使用引用,可以作為外鍵的一個取代辦法。
-          上下文(Context),它是一個名字-對象集合,提供了與名字系統交互的主要操作,如查找、綁定、去綁定。子上下文(subcontext)與它的關系類似文件系統中目錄和子目錄的關系,子上下文被包含在一個上下文中,通過父上下文中的一個名字與子上下文關聯。
-          名字系統和名字空間(Naming Systems and Namespaces),名字系統是相同類型的上下文的集合,它提供名字服務;名字空間,是名字系統中的名字集合,如文件系統的文件名和目錄。
Directory service       目錄服務是名字服務的擴展,它除了關聯名字和對象,還允許對象包含屬性。目錄系統通常以層次結構組織數據。在目錄服務中的主要概念:
-          屬性(Attributes),它屬于目錄對象,它是(名字,值)對,屬性可以有多個值。
-          目錄和目錄服務(Directories and Directory Services),目錄是目錄對象的集合;目錄服務則提供與目錄相關的服務,創建、刪除和修改存放在目錄中的對象的屬性。
-          查找和查找過濾器(Searches and Search Filters),獲取目錄對象的操作就是查找;過濾器是類似查找條件的對象。
基本使用
 
²        注冊JNDI提供者
在使用JNDI之前,需要先獲取JNDI的提供者,并在系統注冊它。與JNDI相關的系統屬性在javax.naming.Context中定義,常用的屬性:
-          java.naming.factory.initial,服務提供者用來創建InitialContext的類名。
-          java.naming.provider.url,用來配置InitialContext的初始url
-          java.naming.factory.object,用來創建name-to-object映射的類,用于NameClassPair和References。
-          java.naming.factory.state,用來創建jndi state的類
對于目錄服務,由于一般需要安全設置,還通常使用:
-          java.naming.security.authentication,安全類型,三個值:none,simple或strong。
-          java.naming.security.principal,認證信息。
-          java.naming.security.credentials,證書信息。
-          java.naming.security.protocol,安全協議名。
使用System.setProperty注冊,如果程序不顯示說明,那么java會在classpath內查找jdni.properties文件來完成注冊。jdni.properties例子:
java.naming.factory.initial=com.codeline.db.MockInitialContextFactory
 
連接服務
注冊之后,就可以實施服務連接了。對于名字服務由InitialContext開始,目錄服務則使用InitialDirContext。它們分別實現了Context和DirContext,這兩個接口分別對應名字服務和目錄服務的接口,也是JNDI中最重要的兩個接口。
連接名字服務:                

?
1
2
3
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,"
com.sun.jndi.fscontext.FSContextFactory");
InitialContext ctx = new InitialContext();

連接目錄服務:

?
1
2
3
4
5
6
7
8
9
Hashtable env = new Hashtable();
 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
 env.put(Context.PROVIDER_URL, "ldap://myserver.com/");
 env.put(Context.SECURITY_AUTHENTICATION, "simple");
 //登錄ldap server需要的用戶名
 env.put(Context.SECURITY_PRINCIPAL, "ldapuser");
 //登錄ldap server需要的密碼
 env.put(Context.SECURITY_CREDENTIALS, "mypassword");
InitialDirContext ctx = new InitialDirContext(env);

 
多服務提供者:如果應用包含多個服務提供者,在連接時略有不同。以名字服務為例

?
1
2
3
4
5
6
Hashtable env = new Hashtable();
 env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
 env.put(Context.PROVIDER_URL, "rmi://myserver.com:1099");
 //使用不同的構造函數
InitialContext ctx = new InitialContext(env);

 
查找對象
不論名字服務還是目錄服務,都是使用lookup來查找對象的。除了可以使用String作為參數之外,lookup還可使用Name接口作為參數。

?
1
Greeter greeter = (Greeter)ctx.lookup("SayHello");

如果想要獲得上下文中所有的對象名字,就使用lis返回NameClassPair列表。NameClassPair包含對象名字和對象類名。如果想要獲得實際的對象實例列表,就使用listBindings,它返回Binding列表。Binding是NameClassPair的子類,它包含對象的實例。
-  list

?
1
2
3
4
5
NamingEnumeration list = ctx.list("awt");
while (list.hasMore()) {
 NameClassPair nc = (NameClassPair)list.next();
 System.out.println(nc);
}

-  listBindings

?
1
2
3
4
5
NamingEnumeration bindings = ctx.listBindings("awt");
while (bindings.hasMore()) {
 Binding bd = (Binding)bindings.next();
 System.out.println(bd.getName() + ": " + bd.getObject());
}

 
對象綁定
- 使用bind添加綁定

?
1
2
Fruit fruit = new Fruit("orange");
ctx.bind("favorite", fruit);

- 使用rebind修改綁定

?
1
2
Fruit fruit = new Fruit("lemon");
ctx.rebind("favorite", fruit);

- 使用unbind去除綁定。

?
1
ctx.unbind("favorite");

 
對象改名
使用rename可以給一個在上下文中的對象改名

?
1
ctx.rename("report.txt", "old_report.txt");

- 獲取屬性
屬性相關的接口是Attribute和Attributes,它們都在javax.naming.directory包內。通過DirContext的getAttributes方法就可以獲得對象的屬性集合,然后使用Attributes的get方法獲得對應的屬性,最后通過Attribute的get方法就可以獲得屬性值。

?
1
2
3
4
5
6
String dn = "uid=me, dc=mycompany, dc=com, ou=customer, o=ExampleApp";
Context user = (Context)ctx.lookup(dn);
//獲得所有屬性
Attributes attrs = user.getAttributes("");
Attribute test= attrs .get("test");
Object testValue= test.get();

上例中獲得的是user的所有屬性,在實際使用過程中,考慮網絡帶寬的影響,可以設置獲取要獲取的屬性列表:

?
1
2
String reqd_attrs = new String[] { "surname", "initials","title", "rfc822mailalias"};
Attributes attrs = user.getAttributes("", reqd_attrs);

 
查找和過濾
使用search方法完成。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public DirContext[] findUser(String initials,String surname,String country,String phone) {
 //構造條件
  BasicAttributes search_attrs = new BasicAttributes();
 search_attrs.put("initials", initials);
 search_attrs.put("sn", surname);
 search_attrs.put("c", country);
 if(phone != null)
  search_attrs.put("phonenumber", phone);
 NamingEnumeration results = initial_ctx.search("ou=Customer,o=ExampleApp", search_attrs);
 LinkedList found = new LinkedList();
 while(results.hasMore()) {
  SearchResults sr = (SearchResults)results.next();
  String name = sr.getName();
  Object ctx = sr.getObject();
  if((ctx == null) || !(ctx instanceof DirContext))
   found.add(initial_ctx.lookup(name));
  else
   found.add(ctx);
 }
 DirContext[] ret_val = new DirContext[found.size()];
 found.toArray(ret_val);
 return ret_val;
}

 
DirContext接口主要過濾方式:

1.使用過濾字符串 

?
1
2
String reqd_attrs = new String[] { "cn", "uid","rfc822mailalias" };
NamingEnumeration results = initial_ctx.search("ou=Customer, o=ExampleApp",search_attrs,reqd_attrs);

 
2.使用SearchControls,獲得更多的控制

?
1
2
3
4
5
6
SearchControls ctrls = new SearchControls();
ctrls.setCountLimit(20);
ctrls.setTimeLimit(5000);
ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration results = initial_ctx.search("cat=books,ou=Products,
o=ExampleApp","title=*Java*",ctrls);

修改屬性
使用DirContext和InitialDirContext的modifyAttributes方法完成。所謂的修改過程,實際就是先構造要修改的屬性列表,然后使用上述方法提交。對于屬性包含多個值時,需要把屬性的不修改的值也要包含,否則服務器會認為那些值不再需要而刪除它們。

?
1
2
3
4
5
6
7
8
9
10
11
public void updateAddress(String dn,String address, String country, String phone) {
  BasicAttributes mod_attrs = new BasicAttributes();
  if(address != null)
   mod_attrs.put("address", address);
   if(country != null)
    mod_attrs.put("c", country);
  if(phone != null)
    mod_attrs.put("phonenumber", phone);
   if(mod_attrs.size() != 0)
   initial_ctx.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, mod_attrs);
}

使用ModificationItem,也可一次進行多個不同的修改操作:

?
1
2
3
4
5
6
7
8
ModificationItem[] mod_items = new ModificationItems[2];
Attribute email = new BasicAttribute("rfc822mailalias", new_email);
ModificationItem email_mod = new ModificationItem(DirContext.ADD_ATTRIBUTE, email);
Attribute addr = new BasicAttribute("address", address);
ModificationItem addr_mod = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, addr);
mod_items[0] = email_mod;
mod_items[1] = addr_mod;
initial_ctx.modifyAttributes(dn, mod_items);

創建上下文
使用createSubcontext方法完成。

?
1
2
3
4
5
6
7
8
9
10
11
BasicAttributes attrs = new BasicAttributes();
attrs.put("initials", initials);
 attrs.put("sn", surname);
 attrs.put("rfc822mailalias", email);
 if(address != null)
  attrs.put("address", address);
 if(country != null)
  attrs.put("c", country);
 if(phone != null)
 attrs.put("phonenumber", phone);
initial_ctx.createSubcontext(dn, attrs);

 
刪除上下文
使用destroySubcontext方法完成。

?
1
initial_ctx.destroySubcontext(dn);

實例
以下再舉一個實例。

在tomcat的conf/server.xml中配置:

?
1
2
3
4
5
6
7
8
<Context path="/jndi">
 
 <Resource name="bean/MyBeanFactory" auth="Container"
   type="com.huawei.jndi.bean.MyBean"
   factory="org.apache.naming.factory.BeanFactory"
   bar="23"/>
 
</Context>

上面就在tomcat中聲明了一個組件,接下來在代碼中可以獲取這個組件:

?
1
2
3
4
5
6
7
8
9
10
11
try
{
 Context initContext = new InitialContext();
 Context envCtx = (Context) initContext.lookup("java:comp/env");
 MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");
 System.out.println(bean.getBar());
}
catch (Exception e)
{
 e.printStackTrace();
}

總結:在tomcat中配置jndi組件,然后在代碼中獲取已配好的組件。

各WEB容器的JNDI實現類是不同的,比如在JBOSS中,JNDI提供類是org.jnp.interfaces.NamingContextFactory,與tomcat是不同的。

這樣看來,JNDI的作用和spring的依賴注入倒是差不多。但是通過JNDI,可以實現跨應用,甚至跨域獲取組件。在服務器A上配置的組件,在另一臺服務器B上,可以通過JNDI獲取到。

spring也提供了對jndi的封裝,使用起來更加方便,以下是一個例子。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- JNDI模板 -->
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
 <property name="environment">
  <props>
   <prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
   <prop key="java.naming.provider.url">10.137.96.212:18199</prop>
   <prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming</prop>
  </props>
 </property>
</bean>
 
<!-- 創建連接工廠 -->
<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
 <property name="jndiTemplate" ref="jndiTemplate" />
 <property name="jndiName" value="TopicConnectionFactory" />
</bean>

先聲明JndiTemplate,配置好目標地址、JNDI服務提供類。然后通過JndiObjectFactoryBean,就可以很方便地獲取JNDI組件,并進行類型轉換。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 九色PORNY真实丨国产大胸 | 国产一级黄色录像 | 久久er99热精品一区二区 | 91混血大战上海双胞胎 | 日本偷偷操 | 色中色官网 | 毛片一级免费 | 娇妻被老外疯狂调教 | 色综合久久日韩国产 | blacked在线播放| 亚洲va在线va天堂va偷拍 | 扒开腚眼子视频大全 | 国产资源中文字幕 | 国产一区视频在线免费观看 | 精品卡1卡2卡三卡免费网站 | 婷婷综合在线 | 亚洲AV 无码AV 中文字幕 | 紧身牛仔裤美女被啪啪久久网 | 无耻之徒第十一季在线观看 | 国产一区二区不卡视频 | 男女拍拍拍免费视频网站 | 国产精品二区高清在线 | 欧美成人禁片在线观看俄罗斯 | 亚洲国产高清视频 | 成人免费一区二区三区在线观看 | 国产成人青草视频 | 鞋奴的视频VK | 成人在线视频国产 | 好紧好爽范冰冰系列 | chinese老太grandma | 国产人成77777视频网站 | 精品久久洲久久久久护士免费 | 91精品国产色综合久久不卡蜜 | 2020国语对白露脸 | 香港三级系列在线播放 | 日韩伦理在线免费观看 | 金莲你下面好紧夹得我好爽 | 久久天堂成人影院 | 无遮挡h肉动漫在线观看电车 | 国产麻豆91欧美一区二区 | 精品国产免费久久久久久婷婷 |