轻松启动独立JNDI服务器(并注册一些资源)

出于测试目的,我正在寻找一种简单的方法来启动独立的 JNDI服务器,并以编程方式将我的javax.sql.DataSource绑定到"java:/comp/env/jdbc/mydatasource"

服务器应该将自己绑定到某个URL,例如:“java.naming.provider.url = jnp:// localhost:1099”(不一定是JNP),这样我就可以从另一个进程查找我的数据源。 我不关心我必须使用哪个JNDI服务器实现(但我不想启动一个成熟的JavaEE服务器)。

这应该很容易,但令我惊讶的是,我找不到任何(工作)教程。

JDK包含RMI注册表的JNDI提供程序 。 这意味着您可以将RMI注册表用作JNDI服务器。 所以,只需启动rmir​​egistry ,将java.naming.factory.initial设置为com.sun.jndi.rmi.registry.RegistryContextFactory ,就可以了。

RMI注册表具有平面命名空间, 因此您将无法绑定到java:/ comp / env / jdbc / mydatasource,但您将能够绑定到某些东西,因此它将接受java:/ comp / env / jdbc / mydatasource,但会将其视为单个组件名称(感谢@EJP)。

我写了一个小应用程序来演示如何执行此操作: https : //bitbucket.org/twic/jndiserver/src

我仍然不知道JNP服务器应该如何工作。

我研究了约翰的代码,现在工作得很好。

在这个版本中,我使用的是JBoss5.1.0.GA的库,请参阅下面的jar列表:

  • jboss-5.1.0.GA \客户\ jbossall-client.jar中
  • jboss-5.1.0.GA \服务器\最小\ LIB \ jnpserver.jar
  • jboss-5.1.0.GA \服务器\最小\ LIB \ log4j.jar
  • jboss-remote-naming-1.0.1.Final.jar(从http://search.maven.com下载)

这是新代码:

 import java.net.InetAddress; import java.util.Hashtable; import java.util.concurrent.Callable; import javax.naming.Context; import javax.naming.InitialContext; import org.jnp.server.Main; import org.jnp.server.NamingBeanImpl; public class StandaloneJNDIServer implements Callable { public Object call() throws Exception { setup(); return null; } @SuppressWarnings("unchecked") private void setup() throws Exception { //configure the initial factory //**in John´s code we did not have this** System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); //start the naming info bean final NamingBeanImpl _naming = new NamingBeanImpl(); _naming.start(); //start the jnp serve final Main _server = new Main(); _server.setNamingInfo(_naming); _server.setPort(5400); _server.setBindAddress(InetAddress.getLocalHost().getHostName()); _server.start(); //configure the environment for initial context final Hashtable _properties = new Hashtable(); _properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); _properties.put(Context.PROVIDER_URL, "jnp://10.10.10.200:5400"); //bind a name final Context _context = new InitialContext(_properties); _context.bind("jdbc", "myJDBC"); } public static void main(String...args){ try{ new StandaloneJNDIServer().call(); }catch(Exception _e){ _e.printStackTrace(); } } } 

要获得良好的日志记录,请使用此log4j属性:

 log4j.rootLogger=TRACE, 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 

要使用独立JNDI服务器,请使用此客户端类:

 import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; /** * * @author fabiojm - Fábio José de Moraes * */ public class Lookup { public Lookup(){ } @SuppressWarnings("unchecked") public static void main(String[] args) { final Hashtable _properties = new Hashtable(); _properties.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); _properties.put("java.naming.provider.url", "jnp://10.10.10.200:5400"); try{ final Context _context = new InitialContext(_properties); System.out.println(_context); System.out.println(_context.lookup("java:comp")); System.out.println(_context.lookup("java:jdbc")); }catch(Exception _e){ _e.printStackTrace(); } } } 

这是一个改编自JBoss遥控样本的代码片段。 样本中的代码(版本2.5.4.SP2)不再有效。 虽然修复很简单,但我花了更多的时间来考虑解决这个问题。 叹。 无论如何,也许有人可以受益。

 package org.jboss.remoting.samples.detection.jndi.custom; import java.net.InetAddress; import java.util.concurrent.Callable; import org.jnp.server.Main; import org.jnp.server.NamingBeanImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StandaloneJNDIServer implements Callable { private static Logger logger = LoggerFactory.getLogger( StandaloneJNDIServer.class ); // Default locator values - command line args can override transport and port private static String transport = "socket"; private static String host = "localhost"; private static int port = 5400; private int detectorPort = 5400; public StandaloneJNDIServer() {} @Override public Object call() throws Exception { StandaloneJNDIServer.println("Starting JNDI server... to stop this server, kill it manually via Control-C"); //StandaloneJNDIServer server = new StandaloneJNDIServer(); try { this.setupJNDIServer(); // wait forever, let the user kill us at any point (at which point, the client will detect we went down) while(true) { Thread.sleep(1000); } } catch(Exception e) { e.printStackTrace(); } StandaloneJNDIServer.println("Stopping JBoss/Remoting server"); return null; } private void setupJNDIServer() throws Exception { // start JNDI server String detectorHost = InetAddress.getLocalHost().getHostName(); Main JNDIServer = new Main(); // Next two lines add a naming implemention into // the server object that handles requests. Without this you get a nice NPE. NamingBeanImpl namingInfo = new NamingBeanImpl(); namingInfo.start(); JNDIServer.setNamingInfo( namingInfo ); JNDIServer.setPort( detectorPort ); JNDIServer.setBindAddress(detectorHost); JNDIServer.start(); System.out.println("Started JNDI server on " + detectorHost + ":" + detectorPort ); } /** * Outputs a message to stdout. * * @param msg the message to output */ public static void println(String msg) { System.out.println(new java.util.Date() + ": [SERVER]: " + msg); } } 

我知道我已经迟到了,但我最终还是像这样一起黑客攻击

 InitialContext ctx = new InitialContext(); // check if we have a JNDI binding for "jdbc". If we do not, we are // running locally (ie through JUnit, etc) boolean isJndiBound = true; try { ctx.lookup("jdbc"); } catch(NameNotFoundException ex) { isJndiBound = false; } if(!isJndiBound) { // Create the "jdbc" sub-context (ie the directory) ctx.createSubcontext("jdbc"); //parse the jetty-web.xml file Map dataSourceProperties = JettyWebParser.parse(); //add the data sources to the sub-context for(String key : dataSourceProperties.keySet()) { DataSource ds = dataSourceProperties.get(key); ctx.bind(key, ds); } } 

你考虑过使用Mocks吗? 如果我没记错,您可以使用Interfaces与JNDI进行交互。 我知道我以前至少曾经嘲笑过他们一次。

作为后备,你可以使用Tomcat。 它不是一个完整的J2EE impl,它启动速度很快,并且很容易配置JNDI资源。 DataSource设置已有详细记录。 这是次优的,但应该有效。

你暗示你发现了非工作教程; 这可能意味着你已经看过这些:

  • J2EE还是J2SE? JNDI适用于两者
  • 使用jnpserver.jar的独立JNDI服务器

我快点走了,但无法让这个工作。 但是,坚持不懈可能会有所作为。

对于本地,一个进程独立的jar purpouses我会使用spring-test包:

  SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); SQLServerConnectionPoolDataSource myDS = new SQLServerConnectionPoolDataSource(); //setup... builder.bind("java:comp/env/jdbc/myDS", myDS); builder.activate(); 

启动日志:

 22:33:41.607 [main] INFO org.springframework.mock.jndi.SimpleNamingContextBuilder - Static JNDI binding: [java:comp/env/jdbc/myDS] = [SQLServerConnectionPoolDataSource:1] 22:33:41.615 [main] INFO org.springframework.mock.jndi.SimpleNamingContextBuilder - Activating simple JNDI environment 

我最近一直在寻找类似的简单启动器解决方案。 “Sun Microsystems的文件系统服务提供商”对我很有帮助。 请参阅https://docs.oracle.com/javase/jndi/tutorial/basics/prepare/initial.html 。

RMI注册表的问题是您需要一个查看器 – 在这里您只需要查看文件内容。

您可能需要fscontext-4.2.jar – 我是从http://www.java2s.com/Code/Jar/f/Downloadfscontext42jar.htm获得的。