下面的例子是使用Sun自带的RefFSContextFactory来存储JNDI信息,可以将RefFSContextFactory想象为一个大的HashMap,里面存储了很多对象的信息,需要时只需要从HashMap获取对象即可。
本例包括4个类,说明如下:
- BindedClass:自定义的实现Referenceable接口的类
- BindedClassFactory:工厂类,能够把一个Reference对象转换为BindedClass对象
- Bind:测试类,用于在JNDI中绑定对象
- Loopup:测试类,用于从JNDI中获取对象
首先需要引入fscontext.jar和providerutil.jar,这是进行测试的前提。
package jndi;
import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.Referenceable; import javax.naming.StringRefAddr; public class BindedClass implements Referenceable { public String value; public BindedClass() { } @Override public Reference getReference() throws NamingException { Reference r = new Reference(this.getClass().getName(), BindedClassFactory.class.getName(), null); r.add(new StringRefAddr("value", this.getValue())); return r; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
BindedClass类是要存储的类,需要实现Referenceable接口的Reference getReference()方法。该Reference指定了创建BindedClass对象的工厂--BindedClassFactory。
package jndi; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; public class BindedClassFactory implements ObjectFactory { @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { if (obj instanceof Reference) { Reference ref = (Reference) obj; String val = (String) ref.get("value").getContent(); BindedClass o = new BindedClass(); o.setValue(val); return o; } return null; } }
BindedClassFactory类将一个Reference对象转换为所需求的BindedClass对象,是创建BindedClass对象具体的类。
package jndi; import java.util.Properties; import javax.naming.Context; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; public class Bind { public static void main(String[] args) throws Exception { Properties ps = new Properties(); ps.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); ps.setProperty(Context.PROVIDER_URL, "file:JNDI_REF"); DirContext ctx = new InitialDirContext(ps); String key = "bind1"; BindedClass b = new BindedClass(); b.setValue("abcdefg"); ctx.rebind(key, b); System.out.println("Binded successfully!"); ctx.close(); } }
Bind类用于绑定对象,ps.setProperty(Context.PROVIDER_URL, "file:JNDI_REF");这就要求工程下面有一个名为JNDI_REF的文件夹,其下有一个后缀为.bindings的文件,记录了所绑定对象的信息。
package jndi; import java.util.Properties; import javax.naming.Context; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; public class Lookup { public static void main(String[] args) throws Exception { Properties ps = new Properties(); ps.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); ps.setProperty(Context.PROVIDER_URL, "file:JNDI_REF"); DirContext ctx = new InitialDirContext(ps); String key = "bind1"; BindedClass o = (BindedClass) ctx.lookup(key); System.out.println(o.getValue()); ctx.close(); } }
Lookup类用于获取所绑定的对象。Bind类中将对象绑定至bind1,这里就查找bind1获取BindedClass对象。
先运行Bind类再运行Lookup类,就可以看到成功的获取到了BindedClass对象。
工程下面有一个名为JNDI_REF的文件夹,其下有一个后缀为.bindings的文件,记录的内容如下:
bind1/RefAddr/0/Type=value bind1/ClassName=lld.test.jndi.BindedClass bind1/RefAddr/0/Encoding=String bind1/FactoryName=lld.test.jndi.BindedClassFactory bind1/RefAddr/0/Content=abcdefg
可以看到该文件记录了绑定类的ClassName,创建绑定类的工厂FactoryName,以及一个类型为String,名为value的属性,可以在创建对象时直接给对象的属性赋值。
数据库的数据源DataSource都实现了Referenceable接口,因此可以通过JNDI来直接获取数据库的数据源,而不必使用JDBC。
下面是使用JNDI获取MySQL数据连接的例子,需要引入MySQL driver.jar。MysqlDataSource位于MySQL驱动的jar包中。
package jndi; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; public class DataSourceJNDI { public static void main(String args[]) throws SQLException { // 初始化名称服务环境 Context ctx = null; try { Hashtable env = new Hashtable(5); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put(Context.PROVIDER_URL, "file:JNDI_REF"); ctx = new InitialContext(env); } catch (NamingException ne) { ne.printStackTrace(); } try { bind(ctx, "jdbc/chidb"); lookup(ctx, "jdbc/chidb"); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } static void bind(Context ctx, String ln) throws NamingException, SQLException { // 创建一个DataSource实例 MysqlDataSource ods = new MysqlDataSource(); ods.setURL("jdbc:mysql://172.16.131.181:13306/NNM5?autoReconnect=true");//需要改为实际的数据库 ods.setServerName("Chicago"); ods.setDatabaseName("NNM5"); ods.setPortNumber(13306); ods.setUser("root"); ods.setPassword("OSSDB123"); // 把DataSource实例注册到JNDI中 System.out.println("Doing a bind with the logical name : " + ln); ctx.bind(ln, ods); System.out.println("Successfully bound"); } static void lookup(Context ctx, String ln) throws NamingException, SQLException { // 从JNDI中查询DataSource实例 System.out.println("Doing a lookup with the logical name : " + ln); DataSource ods = (DataSource) ctx.lookup(ln); System.out.println("Successful lookup"); // 从查询到的DataSource实例中获取数据库连接 Connection conn = ods.getConnection(); // 进行数据库操作 getUserName(conn); // 关闭连接 conn.close(); conn = null; } static void getUserName(Connection conn) throws SQLException { // 生成一个Statement实例 Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery("select propname from rc_properties"); while (rset.next()) System.out.println("Name is " + rset.getString(1)); rset.close(); rset = null; stmt.close(); stmt = null; } }
还可以使用其他软件作为JNDI服务器,如WebLogic,tomcat等。