JNDI详解
JNDI(Java Naming and Directory Interface, Java命名和目录接口),说白了,就是通过配置一些xml文件,方便用户直接调用API使用某些通用的资源。
举个简单的例子,如果在tomcat中部署了很多应用,应用都需要使用同一个数据库,如果每个应用都在代码中配置数据库的连接,肯定是很麻烦的。
所以通过JNDI就可以简单的通过 InitialContext 获取到统一配置的资源,简化代码的编写。
配置
这里说明的内容,不是每次编码必须的步骤,只是先说明一下都有哪些地方涉及到配置。
web.xml
这部分内容配置资源引用,举个例子:
<resource-env-ref>
<description>
资源配置说明
</description>
<resource-env-ref-name>
bean/MyBeanFactory
</resource-env-ref-name>
<resource-env-ref-type>
com.mycompany.MyBean
</resource-env-ref-type>
</resource-env-ref>
在web.xml中可以配置三种形式的资源:
<env-entry> 用于配置一些应用程序的变量,比如参考 tomcat下部署solr。
<resource-ref> 资源引用,通常是一个对象工厂资源,比如典型的JDBC数据源。
<resource-env-ref> 资源环境引用,他是servlet2.4中新引入的特性,在resource-ref的基础上,可以更简单方便的配置信息而不用经过身份验证,比如简单的javabean。
context.xml
这部分定义其引用的资源工厂以及一些必要的额外信息,比如:
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"
factory="org.apache.naming.factory.BeanFactory"
bar="23"/>
...
</Context>
这里需要注意的是,<context>标签有三种配置位置:
1 在conf/server.xml中;
2 在conf/context.xml中;
3 在/webapps/xxx/WEB-INF/context.xml;
这三种的区别是,server.xml与context.xml类似都是所有应用通用的,但是context.xml只是把它分离出来单独形成了一个文件而已。在WEB-INF/下的context.xml则是应用自己的,所以如果不想把某些信息公开,放在这里就可以了。
在<context>中可以配置如下的标签:
<Environment> 配置一些键值对变量,类似于<env-entry>
<Resource> 配置一些资源的类型和变量信息,类似于<resouce-ref>
<ResourceLink> 指定资源链接到全局上下文中的配置,比如在server.xml中配置了全局的一个标签,这里可以直接引入该标签名字。
<Transaction> 添加工厂资源实例
server.xml
这个文件中可以配置<context>标签,前面说过了;还可以配置全局JNDI资源,比如默认的tomcat就配置了一个userdatabase的资源
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
</GlobalNamingResources>
它就是一个全局的配置。
使用
配置好相应的xml文件,就可以在代码中直接通过创建Context实例,例如在配置数据源中:
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
//上面写法都是不变的,下面这行中lookup中的字符串就是配置的JNDI名称,
//比如context中的<resource name="xxx">或者web.xml中的<resource-env-ref-name>
DataSource ds = (DataSource)envCtx.lookup("jdbc/EmployeeDB");
Connection conn = ds.getConnection();
... use this connection to access the database ...
conn.close();
最后参考几个样例,了解一下编码细节。
1 通用JavaBean资源
首先,创建自己的javabean,并配置其构造方法设置初始化值。
然后,配置web.xml中资源引用
接下来,在tomcat conf/context.xml中配置工厂资源引用,并设置初始化的值
最后在JSP中调用lookup方法,获得实例。
由于foo没有在<Resouce>标签中设置值,因此读取的还是默认的值,而bar则为设置的值。
2 Userdatabase使用
userdatabase即用户数据库,主要用于配置用户信息,以供某些应用进行授权验证。
关于其他的配置比如web.xml的Realm配置这里就不多说了,看看server.xml中如何设置全局资源引用:
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
...
<GlobalNamingResources>
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
</GlobalNamingResources>
<Service name="Catalina">
...
<Engine defaultHost="localhost" name="Catalina">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
...
</Engine>
</Service>
</Server>