首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 疑问jboss的jndi名称空间 ,谢谢指导
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-05 21:32:24 楼主
    jboss或其它javaee服务器的jndi名称空间分为几大类:
    1.全局(本机或其它机器都可通过网络访问这个名称空间里面的东东,对命名没有要求);
    2.本jvm能访问的(以java:/开头,只能在同一个jvm内访问);
    3.java:/cmp(只能在本组件内部访问,比如发布此jndi资源的本web程序内部)

    上述分类是我google了很多资源后对常用服务器的jndi分类的一个理解。(不知是否正确),为了验证我的理解,我在jboss里面同时部署了2个web应用a.war,b.war,在这2个web应用里面使用同样的代码列出jndi树,代码如下:
    Enumeration i1 = new InitialContext().listBindings(""); // Global namespace

    Enumeration i2 =new InitialContext().listBindings("java:/"); // java namespace (same VM only)
    Enumeration i3 =new InitialContext().listBindings("java:/comp"); // Component names
    Enumeration i4 =new InitialContext().listBindings("java:/comp/env"); // ENC

    logger.info("global context ");
    for (; i1.hasMoreElements();)
    logger.info(i1.nextElement());

    logger.info("context java:/");
    for (; i2.hasMoreElements();)
    logger.info(i2.nextElement());

    logger.info("context java:/comp/");
    for (; i3.hasMoreElements();)
    logger.info(i3.nextElement());

    logger.info("context java:/comp/env/");
    for (; i4.hasMoreElements();)
    logger.info(i4.nextElement());
    通过比较a.war和b.war 打印出的日志,我发现二者打印出的全局名称空间包含的内容是一致的,Java:/这个名称空间的内容是一致的。a.war的java:/comp内容如下:
    UserTransaction: javax.naming.LinkRef:Reference Class Name: javax.naming.LinkRef
    Type: LinkAddress
    Content: UserTransaction

    2007-09-28 15:50:53,440 INFO [attachweb] env: org.jnp.interfaces.NamingContext:org.jnp.interfaces.NamingContext@7e942f

    b.war的java:/comp内容如下:
    UserTransaction: javax.naming.LinkRef:Reference Class Name: javax.naming.LinkRef
    Type: LinkAddress
    Content: UserTransaction

    2007-09-28 15:51:25,368 INFO [syn_cen] env: org.jnp.interfaces.NamingContext:org.jnp.interfaces.NamingContext@626028

    发现分别从a.war,b.war中访问并列出java:/comp的内容是不同的。我发现的矛盾是:在整个jndi空间内,a.war,b.war的java:/comp是同一个吗?至少它们都属于java:/这个父亲空间,而同一个父亲空间(这里是java:/)怎么可能包括2个同名的java:/comp子空间呢?如果a.war,b.war的java:/comp是同一个,为何打印出来的内容又不一样?

    在应用服务器的jndi空间里,java:/comp是组件(包括web,ejb)的私有空间,是为了起到隔离各组件名称空间的作用,只要是在各组件私有空间绑定的资源,即使名字和其它组件私有空间的名称相同也不会引起冲突。那么从a.war,b.war里面lookup ("java:/comp")的时候,jndi服务器怎样区分呢属于不同组件的java:/comp呢?jndi树到底是怎样组织的?

    20  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-07 22:13:111楼 得分:0
    各位j2ee老师,请指导!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-08 12:54:132楼 得分:0
    JBoss中java:/comp的隔离是通过线程的上下文类加载器和Context建立映射关系实现。JBoss系统中保存着线程的类加载器和java:/comp的对应关系,当a.war中调用lookup查找java:/comp或者子上下文时,JBoss系统首先会获取当前线程的上下文类加载器,然后从建立的映射中获取该类加载器对应的java:/comp,从而起到隔离a.war和b.war中java:/comp的效果。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-09 12:05:343楼 得分:0
    java:/comp 应该是java:/的子名称空间。每个应用(如a.war)都有自己独立的java:/comp,为何我打印java:/空间内的所有东东,只看到一个comp这样的子空间,按理说它该有a.comp,b.comp,c.comp(这里名称只是举例)这样多个java:/comp


    谢谢jbossweek的指导!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-10 13:27:324楼 得分:0
    1、comp是java命名空间中的名称,绑定的只是一个指向EncFactory的引用,而不是子上下文。
    2、EncFactory中保存着线程上下文的类加载器和各个web应用java:comp命名空间的对应关系。

    因而listBindings("java:/")时只能列出一个comp,该comp是EncFactory中当前线程上下文的类加载器对应的那个comp。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-10 18:23:555楼 得分:0
    搜索
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-10 18:24:136楼 得分:0
    赞JBossWeek的解释。zaozaowang的问题,要求对JBoss JNDI服务的实现机制有一定的了解。我参考了JBoss的部分源代码,做一点补

    充。

    java:comp下绑定的是组件(可以认为就是EJB)的ENC。ENC是组件唯一的,也就是说每个组件都有自己特定的ENC。为了实现这样的机

    制,JNDI实现需要解决以下三个问题:
    1、需要隔离不同组件的ENC。
      这一点是显然的,每个组件都需要有自己的ENC对象。
    2、仅仅实现隔离是不够的,还要让各个组件能够“找到”属于自己的ENC。
      这一问题也好解决。所有组件的ENC都保存在一个类似Map的地方,每个组件持有自己的key,就可以找到自己的ENC。
    3、这个“找到”的过程是对程序员透明的。
      这个问题很重要,也是体现JavaEE思想的地方。获取某个组件的ENC的过程,就是查找Map的过程。学过数据结构的都知道,查找

    Map是需要提供key的。但是程序员在编写Bean方法的时候,他不需要知道Bean的key,也无需提供key,而是以相同的方式获得该Bean

    特定的ENC。尽管每个Bean都有自己的key,但是程序员在获取ENC的时候并不需要提供这个key。进一步说,key的分配和管理肯定是

    容器的责任,而不可能是程序的责任。因为程序员只是编写自己的Bean,他无法保证key的唯一性。因此程序员也只能以某种固化的

    方式获取Bean的ENC。事实上,程序员只要在Bean的方法中使用如下代码:
      InitialContext ctx = new InitialContext();
      Context  enc = (Context)ctx.lookup("java:comp/")。  //enc就是指向该Bean的ENC的引用

    让我们看看JBoss是如何解决这三个问题的。
    1、对于第一个问题:
      每个Bean都会拥有一个自己的NamingContext对象,它就是该Bean的ENC。这里的“拥有”并不是说NamingContext是该Bean的一个

    成员变量。ENC其实是被保存在ENCFactory类的静态WeakHashMap中。
      那么,Bean的ENC什么时候被创建呢?答案是,在JBoss部署这个Bean的时候。部署Bean的过程,其实就是创建该Bean的容器对象

    。在创建容器的过程中,会创建Bean的ENC,以及设置ENC的内容,如环境入口变量、EJB引用、资源工厂引用等。创建好的ENC保存在

    ENCFactory的WeakHashMap中。
    2、对于第二个问题:
      每个Bean的NEC都有一个对应的key,根据该key,可以在ENCFactory中查找到ENC。在JBoss中,每个容器对象都有一个成员变量

    classloader。这个classloader是容器唯一的。而每个Bean与容器对象也是一一对应的关系,JBoss会为每个Bean组件创建一个容器

    对象。因此,classloader也是Bean唯一的,从而这个classloader就称为了ENC的key。
    3、对于第三个问题:
      在上面的那段代码中,并没有出现classloader,但是InitialContext的lookup方法一定会使用classloader作为key的。那么

    classloader是怎么传递给lookup方法的呢?答案是通过线程上下文类加载器。
      InitialContext.loopup方法在Bean的方法中执行,Bean方法总是被客户调用的。在JBoss中,客户对Bean的调用并不是直接到达

    Bean实例的,而是有很长一段中间过程。这个调用会经历客户端代理、客户端拦截器拦截器链、分离调用器,然后到达容器对象,接

    着又经历容器拦截器链,最后到达Bean实例的Bean方法。在调用达到容器对象时,容器会将自己的classloader设置当前线程的上下

    文类加载器。当Bean方法调用InitialContext的lookup方法时,还是处于同一个线程中。loohup方法发现要查找的jndi名称是

    以"java:com"开头时,它就将查找任务委派给ENCFactory对象,并以当前线程上下文类加载器作为key,提供给ENCFactory。

    ENCFactory就可以根据key,在WeakHashMap中查找相应的ENC,并作为返回值。
      因此,ENC的key是以当前线程上下文类加载器的方式,“隐式”传递给InitialContext.lookup方法。这个过程有容器完成,与

    Bean没有关系,对程序员自然也就是透明的了。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-11 12:41:297楼 得分:0
    jarfield分析很清楚啊,欢迎常来交流和指导!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-11 14:26:508楼 得分:0
    终于得以释疑。非常感谢各位大侠。
    以后可以多来讨教jboss的知识了。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-11 15:04:579楼 得分:0
    问题又来了,我使用如下函数:
    public static void viewAll(Context ctx, String level) {
    try {
    NamingEnumeration nameE = ctx.list("");
    NameClassPair binding;
    while (nameE.hasMore()) {
    binding = (NameClassPair) nameE.next();
    Object obj = ctx.lookup(binding.getName());
    if (obj != null && obj instanceof Context){
    logger.info("is a context:" + level + binding.getName());
    viewAll((Context) obj, level + "---");
    }else{
    logger.info("is not a context:" + level + binding.getName());
    }
    }
    } catch (Exception e) {
    System.out.println("error." + e.getMessage());
    }
    }

    将java:/这个context中的内容打印出来,以下是部分结果:
    ...........
    is not a context:TransactionPropagationContextExporter
    14:33:36,169 INFO  [syn_cen] is not a context:ConnectionFactory
    14:33:36,169 INFO  [syn_cen] is not a context:DefaultJMSProvider
    14:33:36,170 INFO  [syn_cen] is not a context:testds
    14:33:36,171 INFO  [syn_cen] is not a context:XAConnectionFactory
    14:33:36,172 INFO  [syn_cen] is not a context:Mail
    14:33:36,174 INFO  [syn_cen] is a context:timedCacheFactory
    14:33:36,174 INFO  [STDOUT] error.org.jboss.util.TimedCachePolicy
    14:33:36,175 INFO  [syn_cen] is not a context:SecurityProxyFactory
    14:33:36,175 INFO  [syn_cen] is a context:comp
    14:33:36,176 INFO  [syn_cen] is not a context:---UserTransaction
    .....................

    1.可见java:/这个context确实包括一个叫做comp的子context;这和jbossweek的解释“comp是java命名空间中的名称,绑定的只是一个指向EncFactory的引用,而不是子上下文”是不符合的。

    2.java:/中只有一个comp ,敢情这个与我用lookup("java:/comp")查找到的不是同一个comp玩意了。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-11 18:10:5910楼 得分:0
    顶一下。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-11 18:46:0211楼 得分:0
      赞zaozaowang追根究底的精神!JBoss JNDI服务的实现很复杂,大量地使用工厂模式,很多工厂类的类名都是以系统属性的方法提供,
    所以从源代码中追踪函数的调用关系很麻烦,所以整个机制我弄得不是很清除,下面是我的一点理解,大家看看是不是合理。
      首先,我来介绍一下JNDI服务中的Reference对象。
      一般来说,我们可以把一个对象注册到JNDI服务中,通过调用InitialContext的bind和rebind方法即可。这个被注册的对象,我们称之为
    “被引用对象”,它是驻扎在内存中的运行时对象。JNDI服务的功能不是仅限于此,它还可以注册各种资源,例如网络打印机。这类资源可不是
    内存中可以找到的运行时对象,所以它们不能直接注册到JNDI的命名空间中,而必须以某种间接的方式注册。以网络打印机为例,JNDI服务可以
    注册它的IP地址和端口,有了通信地址,总是可以访问到网络打印机的。
        在JNDI API的javax.naming包中,有一个Reference类,它就是代表这些网络打印机这类资源的。Reference对象包含一系列RefAddr对象,RefAddr对象就表示资源的通信地址。Reference对象中还包含被引用对象的类名和对象工厂的类名,当被引用对象被lookup的时候,对象工厂
    会实时创建被引用对象的实例。举个列子,如果客户需要通过JNDI去获得一个唯一的ID,那么我们在JNDI中注册一个IDFactory。这个工厂以
    递增的次序创建ID。当客户调用lookup方法获得ID的时候,每次得到的是不同的、唯一的ID。
        同样,EJB的ENC也是采用这种机制。JBoss提供了一个对象工厂ENCFactory。ENCFactory可以创建NamingContext对象(即ENC)。其方法就是
    在一张HashMap中保存classloader和ENC的对应关系。当客户查询时,就根据当前线程上下文类加载器,在HashMap中查找并返回相应的ENC对象。
        说到这里,大家应该能猜测到,java:cmop下绑定的是一个Reference对象,这个对象中包含了ENCFactory的类名org.jboss.naming.ENCFactory。返回的ENC对象其实是由ENCFactory提供的。
        现在回答zaozaowang的两个问题:
        1、jbossweek的解释“comp是java命名空间中的名称,绑定的只是一个指向EncFactory的引用,而不是子上下文”,是完全正确的。“指向EncFactory的引用”就是那个包含ENCFactory类名的Reference对象。它的类型是javax.naming.Reference,而不是上下文Context。
        2、java:/的comp,与你lookup的java:/comp,绝对是同一个名字。那么为什么lookup返回结果是Context类型呢?因为,对于Reference对象,lookup方法不会直接返回它,否则是没有意义的。lookup方法根据java:comp找到Reference对象后,进一步解析,调用ENCFactory的getObjectInstance,以这个方法的返回值作为查询结果,返回给客户。而这个方法的返回值就是ENC对象,它的类型就是Context。
        总上所述,在某些情况下,JNDI命名空间中绑定的对象,与lookup返回的结果,并不一定就是同一个对象,Refernce对象是一个“间接”的桥梁。

    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-11 19:02:0512楼 得分:0
    简单的说,绑定在java:comp其实是一个Reference对象,但是lookup在查询java:comp这个名字的时候,没有直接返回Reference对象,而是做了进一步处理,返回了ENC对象,其类型是Context。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-12 12:50:0813楼 得分:0
    谢谢,我也不再深究了。
    希望以后各位能多多指导,大家一起长进。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-10-13 21:49:1114楼 得分:0
    奇怪了,我给了分,然后点结贴。竟然未能结贴,也未能给分。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-23 13:09:3015楼 得分:0
    学习
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-26 10:36:5516楼 得分:0
    欢迎加入Java技术支持QQ群号:62071429
    修改 删除 举报 引用 回复

    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved