The
Java Naming and Directory Interface
(JNDI) is mainly used for accessing resources that are managed by a container.
JEE application servers expose JDBC data sources, JMS connection factories,
JTA user transactions among others to applications via JNDI. Each resource has
a global unique JNDI name. For example jdbc/ORA45X2
could be a data source.
Section EE.5.2 of the
JEE 7 specification
says that application components should not lookup resources using the global
JNDI name but use a local JNDI naming context instead. For example, the name
space java:comp
provides a local context per application component. Each EJB
is a component but for compatibility reasons all components in a web module
share the same context. The other name spaces java:module
, java:app
and
java:global
are usually not used when an application contains only a web
module, for example when EJBs are not used.
Resource references are created as environment entries in the java:comp/env/
name space. They provide a layer of indirection and get mapped to JNDI names
during deployment. This is either done by the deployer or using a
container-specific deployment descriptor that is shipped by the application.
In this example java:comp/env/jdbc/customer_db
is mapped to jdbc/ORA45S2
.
WebSphere Application Server logs a J2CA0294W warning in debug mode, if a direct JNDI lookup is done.
For web applications,
resource references
must be defined in WEB-INF/web.xml
:
<web-app id="example" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="[...]">
<resource-ref>
<description>Customer master data</description>
<res-ref-name>jdbc/customer_db</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
Application code then has to look up
java:comp/env/jdbc/customer_db
like this:
InitialContext context = new InitialContext();
DataSource customerDataSource = (DataSource) context.lookup(
"java:comp/env/jdbc/customer_db");
The Spring Framework 3.0 helps you
with JNDI lookups. You can use
<jee:jndi-lookup>
in your application context:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="[...]">
<jee:jndi-lookup id="customerDataSource"
jndi-name="jdbc/customer_db"
expected-type="javax.sql.DataSource" />
</beans>
Spring prepends the java:comp/env/
name space when it’s not already present
and the resource-ref
attribute is not set to false
. It falls back to the
global JNDI name if the resource is not found in the local context so you
should not use the java:comp/env/
prefix for a JNDI lookup with Spring.
The deployment descriptor for a
Servlet 2.5
application on WAS 7 and above is WEB-INF/ibm-web-bnd.xml
. You can specify
the bindings from local environment entries to global JNDI names so the
deployer doesn’t have to.
<web-bnd version="1.0"
xmlns="http://websphere.ibm.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="[...]">
<virtual-host name="default_host" />
<resource-ref name="jdbc/customer_db"
binding-name="jdbc/ORA45X2" />
</web-bnd>
For a JTA
UserTransaction
, the name java:comp/UserTransaction
must be used. There’s
no global JNDI name for the user transaction since the local transaction
context is required. For this reasons, unmanaged threads without a JEE context
can not participate in a container-managed transaction.