日期:2014-05-20  浏览次数:20666 次

java总结(三)——jndi在j2ee和j2se中的应用

    JNDI,Java命名和目录接口,允许应用程序通过公共接口访问各种命名和目录服务。下图显示了JNDI架构。如JDBC(Java数据库连接),JNDI是不是服务,而是一组接口; 它允许应用程序使用一个标准化的API来访问许多不同的目录服务供应商。就像使用JDBC,那么JDK包含了JNDI接口,但不包括JNDI服务提供者 - 尽管Sun Microsystems公司提供的适配器,用于连接到现有的目录服务供应商,如LDAP(轻量级目录访问协议),DNS(域名服务)和CORBA。但是,您可以使用多种免费或开源的JNDI供应商在你的J2SE(Java 2平台标准版)的应用程序之一。


    JNDI是保存在一起的J2EE(Java2平台企业版)应用的胶水。JNDI被设计用来支持高动态应用程序组装和部署,与组件不断添加和更新,无需重建整个系统。命名服务有助于通过充当中央登记成分组织的企业应用程序。J2EE应用程序通常使用JNDI在几个方面:

·        随着存储应用程序的配置信息在一个集中,层次型数据库的一种手段

·        作为应用程序组件之间共享的活动对象,它可以在不同的JVM或者在不同系统上运行的存储库

·        作为一个接口与现有的目录服务,如LDAP(使用特定的提供给外部服务)

·        作为一个轻量级的,分层数据库,用于存储瞬态应用程序状态

    像J2EE应用程序,更大或更动态的J2SE应用程序可以受益于松散耦合和动态绑定提供了一个积极的目录服务。

一个简单的JNDI例子

    从JNDI名称空间存储和检索对象是相当简单的; 你第一次得到一个JNDI 命名上下文,然后使用bind()方法和lookup()方法来存储和检索对象,如清单1所示:


    清单1。从JNDI名称空间存储和检索对象

 

  importjavax.naming.*;
  public voidcreateName() throws NamingException {
    Context context= new InitialContext();
   context.bind("/config/applicationName", "MyApp");
  }
  public StringgetName() throws NamingException {
    Context context= new InitialContext();
    return (String)context.lookup("/config/applicationName");
  } 


 

    清单1演示了最常见的JNDI操作-创建一个JNDI上下文,在上下文绑定的对象,然后从上下文检索对象。请注意,JNDI名称空间和客户端可能驻留在不同的JVM,并Bind()和lookup()的调用可能会同样发生在不同的JVM。一个JNDI提供者使用了多种技术,包括系列化,以确保对象可以从JVM移动到JVM中,但仍然可以检索到它的原始形式。

    清单1中的代码片段有几个隐藏的假设:JNDI如何知道使用哪个提供商创建上下文时?对于需要身份验证提供程序,凭据从何而来?一般情况下,您可以通过设置在系统属性中的JNDI几个特定的属性指定供应商及其他连接参数,或通过设置他们在jndi.properties中的文件。此外,任何给定的供应商可能无法绑定或检索任意对象。例如,一些供应商,如DNS提供商,是只读的,而有些供应商可能会更灵活一些,他们可以绑定的对象的类型。大多数厂商提供的JNDI提供商可以存储和检索实现的java.io.Serializable,java.rmi.Remote的,或javax.naming.Referenceable的一个对象

隐藏的JNDI提供

    在上图所示的JNDI供应商都有一个共同点 - 他们的请求委托给外部的目录服务,如LDAP。然而,此图没有显示JNDI提供者的一个重要类型:内置于所有J2EE容器,它存储的目录信息在内部数据库中的JNDI提供者。当我们谈论在J2EE应用程序中使用JNDI,我们通常所说的这个容器提供的供应商。

如何J2EE使用JNDI?

    J2EE应用程序是组装出来的组件。该方法的组件的配置和相互连接是在部署时指定的;大部分信息都存储在JNDI名称空间。J2EE应用程序使用JNDI来存储配置信息(如字符串和数值常量),无状态的对象(包括对象工厂),和EJB(E??nterprise JavaBean组件)home接口。

    JNDI是,它允许您构建J2EE应用了如servlet,JSP页面(JavaServer页面),和EJB组件的胶水。在J2EE应用程序中,每个组件发现其他组件无法通过静态连接,而是通过JNDI查找。J2EE应用程序允许部署时间,同时保持型和链路安全通过让每个组件出口的外部组件和资源,它需要一个列表绑定。部署者确保每个进口都有正确类型的应用程序中的相应部分。J2EE容器包括工具,以帮助您正确做到这一点。

如何J2SE应用程序使用JNDI?

     像J2EE应用程序,J2SE应用程序可以使用JNDI作为命名的配置参数,对象和对象工厂的共享存储库。工厂创建模式中使用JNDI非常合适,因为你可以存储你的工厂在JNDI名称空间。J2SE应用程序也可以使用JNDI作为一个更强大,功能丰富,并集中更换为RMI(远程方法调用)。

    大多数J2SE应用程序的配置文件,这些文件存储无论是作为属性文件或XML文档加载其配置信息。这些配置文件中指定的各种配置信息; 一些更复杂的应用程序存储信息的实例化对象,如类名和构造函数的参数,在配置文件中。

    使用JNDI来存储常量,对象和对象工厂相对于传统的配置机制有些优势。由于大多数的JNDI提供者是网络访问的,你不需要保持一个组配置文件一致的每个主机在分布式应用程序。此外,使用反射来实例化一个对象时,需要更多的代码(尤其是更多的错误恢复代码)不能简单地检索出该对象JNDI名称空间中。虽然使用JNDI一般无须从配置信息实例化一个对象(当你填入的命名空间,一般在应用程序启动时),这种复杂性被分解远离大多数的应用程序代码,它可以简单地从JNDI名称空间检索所需的对象。

    另一个原因在分布式应用程序使用JNDI而不是配置文件是因为一个配置文件的信息可能是敏感的,例如用于数据库访问的密码。通过存储数据源的JNDI名称空间,你可以提供给整个应用程序的数据库连接,而不会使密码提供给整个应用程序。(例如,PoolMan包,一种广泛使用的开源连接池包,存储一个数据源对象中的JNDI名称空间(如果有)。)

    使用JNDI与J2SE应用程序,您首先需要一个JNDI提供者,因为JDK中不包括的。如果你只是想使用JNDI来访问外部的目录,例如LDAP,则可以使用Sun提供的供应商之一。但通常情况下,你会希望有一个独立的供应商,有几个你可以使用。

一个独立的JNDI提供

    JBoss的开源J2EE服务器包括一个JNDI供应商(JNP),可以作为一个独立的服务运行; 它提供了一个极好的轻量级网络访问的JNDI服务。JNP采用内存数据库来存储对象,所以命名空间的内容并不在服务重新启动仍然存在。您可以轻松地自行运行JNP或配置JBoss容器,开始只有JNP服务。

选项??1配置JNP服务器JBoss的服务

    JBoss应用服务器是建立在JMX(Java管理扩展)框架; 该框架允许应用程序服务进行模块化为JMX MBean的,它可以启动和管理独立。该文件jboss.jcml包含的mbeans容器启动时,将加载的列表。JBoss的默认配置包括50多个MBean的,但如果你指定jboss.jcml应该只包含清单2中所示的单报关,然后启动JBoss服务器,服务器将只加载了JNDI提供者,没有其他的J2EE应用服务:

清单2。JNDI只jboss.jcml文件

 

<?xml version="1.0"encoding="UTF-8"?>
<server>
  <mbeancode="org.jboss.naming.NamingService"
        name="DefaultDomain:service=Naming">
    <attributename="Port">1099</attribute>
  </mbean>
</server>


 

选项??2。配置JNP服务器独立

    JNP也可以作为一个独立的服务器应用程序运行。要配置它是这样,你需要两个jar文件:

·        jnpserver.jar -从JBoss分布,在lib / ext目录目录

·        log4j.jar -广泛使用的日志工具,来自Apache Jakarta项目; 你还会发现它在JBoss分布在lib / ext目录

此外,你需要一个log4j.properties文件; 清单3显示了一个简单的问题。这个文件应该通过类路径是可访问:


清单3。简单的log4j.properties文件 

 # Use aConsoleAppender -- write log data to standard out
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p%c %x - %m%n

    要运行JNP服务器在独立模式下,确保log4j.jar文件时,jnpserver.jar文件,包含目录log4j.properties都在你的classpath中。然后,启动JNP服务器,如下所示:

                                            javaorg.jnp.server.Main

     您还可以使用org.jnp.server对象到应用程序的JVM中启动JNDI服务。

使用JNDI服务

    一旦JNP服务器正在运行,你可以配置你的应用程序使用JNP通过包括JNP-client.jar的文件在classpath和指定java.naming.provider.urljava.naming.factory.initial无论是在系统属性属性或的jndi.properties文件。清单4显示了一个示例的jndi.properties文件:

清单4。的jndi.properties文件

 

 java.naming.provider.url=jnphost.mycompany.com:1099
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming

    下面的示例显示了如何你可以用字符串,整数,并在属性中指定的对象值参数文件填充一个JNDI名称空间在应用程序启动时间,以及应用程序组件如何能找回这些属性。为了简便起见,清单5A假设方法的存在解析XML配置文件,省略了错误处理代码:

清单5A。从配置文件中加载一个JNDI名称空间

 

 public voidloadJNDI() {
    Context context= new InitialContext();
    ConfigItem[]items = getConfigItems();
    for (int i=0;i<items.length; i++) {
      Objecto=null;
      if(items[i].getType().equals("Integer"))
        o = Integer.decode(items[i].getValue());
      else if(items[i].getType().equals("String"))
        o =items[i].getValue();
      else if(items[i].getType().equals("Object"))
        o =Class.forName(items[i].getValue()).newInstance();
     context.bind(items[i].getName(), o);
    }
  }

 

清单5b所示。示例XML配置文件

 

  <config>
    <itemname="config/screen/resolutionX" type="Integer"
         value="1024" />
    <itemname="config/screen/resolutionY" type="Integer"
         value="768" />
    <itemname="converters/html" type="Object"
         value="com.mycompany.converters.HtmlRenderer" />
    <itemname="converters/pdf" type="Object"
         value="com.pdfmonger.PdfRenderer" />
  </config>

 

清单5C。从JNDI检索和使用对象

 

public void convert(InputStream in, OutputStream out) {
    // Retrieve the converter object fromJNDI
    Context context = newInitialContext();
    Renderer renderer = (Renderer)context.lookup("converters/html");
    // Use the converter object
    renderer.convert(in, out);
  }

    正如你可以看到,从JNDI中检索对象是相当方便,简单。通过使用JNDI来存储配置信息,无状态对象或对象的工厂,你可以轻松地构建灵活的应用程序包含了配置的复杂性在一个地方,同时,即使是分布式应用程序。(如果您的组件从JNDI名称空间访问对象,在组件的Javadoc中记录这些依赖关系。)

JNDI是不是只是用于J2EE

    尽管JNDI客户端接口是J2SE发行版的一部分,大多数的J2SE应用程序不使用JNDI。那些做一般只使用JNDI来访问外部的目录服务(如LDAP)。然而,J2SE应用程序也可以使用部署时绑定,只有J2EE应用程序通常都使用迄今为止功能。有了这样JNP可自由查看的JNDI提供者的实现,需要一个命名服务的任何应用程序可以拥有一个。


 

5楼akkzhjj昨天 13:33
译!了解了解
4楼zs15932616453昨天 23:57
非常不错,学习了!
3楼gwblue昨天 15:33
学习了总结的很好!
2楼tang_huan_11前天 10:54
提前学习一下,总结得很棒
1楼lfmilaoshi前天 23:07
你对J2EE的认识真的是越来越深刻。