【问题标题】:Lookup JNDI names outside of java:comp/env on Tomcat?在 Tomcat 上的 java:comp/env 之外查找 JNDI 名称?
【发布时间】:2019-07-19 04:41:11
【问题描述】:

我正在使用最初为 IBM WebSphere 设计的应用程序,但我也想将它托管在 Tomcat 上。该应用程序无法更改,并且正在执行new InitialContext().lookup("servername"),它适用于 WebSphere。

但是在 Tomcat 上,当我在特定于应用程序的上下文 xml 中指定 <Environment> 名称时,它们会以 java:comp/env 为前缀,并且上面的查找找不到这些名称。

它将在容器中运行,所以如果我必须更新 server.xml 没有问题,当然还有应用程序特定的上下文 xml。

如何让 Tomcat 返回lookup("servername") 上的字符串?

【问题讨论】:

  • 很奇怪。我在Tomcat source code 中看到的唯一内容实际上是丢弃任何JNDI 名称上的java:comp/env 前缀。我看不到它添加的地方。这可能是因为 Tomcat 提供了一个基本的 JNDI 上下文,而不是 EJB 容器提供的工业级 JNDI 上下文。
  • Christopher,我相信它会创建 java:comp/env here 并将名称放入其中 here
  • 呃,我可能没有假设整个字符串在源代码中是连续的:)
  • 我正在尝试实现自定义 InitialContextFactory 作为解决方法。我可以让 Tomcat 使用它,但我还不能让它返回 Context 已经在java:comp/env。如果我能得到它,我会发布代码作为答案。

标签: java tomcat jndi


【解决方案1】:

看起来 Tomcat 被硬编码为以这种方式运行。

但它不必保持这种状态。加入Tomcat user's mailing list 并询问是否有特定原因导致事情如此发展。如果没有特定原因将环境条目限制为 java:comp/env 命名空间,那么我怀疑代码更改(可能涉及新的配置选项)肯定是可能的。

【讨论】:

    【解决方案2】:

    作为一个hack,我创建了这个InitialContextFactory,它只是将字符串名称的查找委托给System.getenv()(环境变量)。这是非常不安全的,并且会破坏正确使用命名的应用程序,因此我不建议将其用于生产或特定用例之外。或者真的对任何人。

    尽管如此,通过使用它,我能够让(String) new InitialContext().lookup("servername") 在命令行中通过set servername=blah 返回特定值blah

    import java.util.Hashtable;
    
    import javax.naming.Binding;
    import javax.naming.Context;
    import javax.naming.Name;
    import javax.naming.NameClassPair;
    import javax.naming.NameParser;
    import javax.naming.NamingEnumeration;
    import javax.naming.NamingException;
    import javax.naming.spi.InitialContextFactory;
    
    public class EnvironmentInitialContextFactory implements InitialContextFactory {
    
    
        public Context getInitialContext(Hashtable<?,?> environment) throws NamingException {
    
            return new Context() {
    
                public Object lookup(String name) throws NamingException {
    
                    return System.getenv(name);
    
                }
    
                public Object lookup(Name name) throws NamingException { return null; }
                public void bind(Name name, Object obj) throws NamingException {}
                public void bind(String name, Object obj) throws NamingException {}
                public void rebind(Name name, Object obj) throws NamingException {}
                public void rebind(String name, Object obj) throws NamingException {}
                public void unbind(Name name) throws NamingException {}
                public void unbind(String name) throws NamingException {}
                public void rename(Name oldName, Name newName) throws NamingException {}
                public void rename(String oldName, String newName) throws NamingException {}
                public NamingEnumeration<NameClassPair> list(Name name) throws NamingException { return null; }
                public NamingEnumeration<NameClassPair> list(String name) throws NamingException { return null; }
                public NamingEnumeration<Binding> listBindings(Name name) throws NamingException { return null; }
                public NamingEnumeration<Binding> listBindings(String name) throws NamingException { return null; }
                public void destroySubcontext(Name name) throws NamingException {}
                public void destroySubcontext(String name) throws NamingException {}
                public Context createSubcontext(Name name) throws NamingException { return null; }            
                public Context createSubcontext(String name) throws NamingException { return null; }
                public Object lookupLink(Name name) throws NamingException { return null; }
                public Object lookupLink(String name) throws NamingException { return null; }
                public NameParser getNameParser(Name name) throws NamingException { return null; }
                public NameParser getNameParser(String name) throws NamingException { return null; }
                public Name composeName(Name name, Name prefix) throws NamingException { return null; }
                public String composeName(String name, String prefix) throws NamingException { return null; }
                public Object addToEnvironment(String propName, Object propVal) throws NamingException { return null; }
                public Object removeFromEnvironment(String propName) throws NamingException { return null; }
                public Hashtable<?, ?> getEnvironment() throws NamingException { return null; }
                public void close() throws NamingException {}
                public String getNameInNamespace() throws NamingException { return null; }
    
            };
    
        }
    
    }
    

    编译该类,并将其添加到 CLASSPATH 和系统属性中,方法是将这些行添加到 setenv.bat(在 %CATALINA_HOME%/bin/ 中创建):

    set CLASSPATH=C:\path\to\compiled\class
    set CATALINA_OPTS=-Djava.naming.factory.initial=EnvironmentInitialContextFactory
    

    【讨论】:

    • 如果你只是想把服务器名输入JVM,为什么不使用系统属性呢? SET CATALINA_OPTS=-Dservername=foo 然后System.getProperty?这不需要任何自定义代码。
    • Christopher,要部署的应用程序正在查找(String) new InitialContext.lookup("servername"),无法修改。该应用程序是围绕在 WebSphere 上托管而设计的。所以这个问题都是关于如何在 Tomcat 上部署相同的应用程序,以使现有的查找返回一个有意义的值。
    • 好吧,接缝有点合理,然后:)
    【解决方案3】:

    我正在重新审视这个(我是提问者)。受this answer 的启发,我决定改用ServletContextListener

    总而言之,您不能让 Tomcat 将环境资源放在 java:comp/env/ 之外,但您可以从那里读取它们并“在任何地方”重新分配它们。

    当 ServletContext 初始化时,我的监听器只是重新绑定它们:

        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            Context ctx = new InitialContext();
            ctx.bind("servername", ctx.lookup("java:comp/env/servername"));
        }
    

    这是一个更好的解决方案 - 它不会影响部署上下文之外的任何内容。

    也可能只重新绑定 comp/env/ 命名空间中的所有名称,以创建更通用的侦听器。现在我只是绑定单个名称,因为应用程序使用的名称很少。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-29
      • 1970-01-01
      相关资源
      最近更新 更多