WildFly offers several mechanisms to retrieve components by name. Every WildFly instance has it's own local JNDI namespace (java:) which is unique per JVM. The layout of this namespace is primarily governed by the Java EE specification. Applications which share the same WildFly instance can use this namespace to intercommunicate. In addition to local JNDI, a variety of mechanisms exist to access remote components.
- Client JNDI - This is a mechanism by which remote components can be accessed using the JNDI APIs, but without network round-trips. This approach is the most efficient, and removes a potential single point of failure. For this reason, it is highly recommended to use Client JNDI over traditional remote JNDI access. However, to make this possible, it does require that all names follow a strict layout, so user customizations are not possible. Currently only access to remote EJBs is supported via the ejb: namespace. Future revisions will likely add a JMS client JNDI namespace.
- Traditional Remote JNDI - This is a more familiar approach to EE application developers, where the client performs a remote component name lookup against a server, and a proxy/stub to the component is serialized as part of the name lookup and returned to the client. The client then invokes a method on the proxy which results in another remote network call to the underlying service. In a nutshell, traditional remote JNDI involves two calls to invoke an EE component, whereas Client JNDI requires one. It does however allow for customized names, and for a centralised directory for multiple application servers. This centralized directory is, however, a single point of failure.
- EE Application Client / Server-To-Server Delegation - This approach is where local names are bound as an alias to a remote name using one of the above mechanisms. This is useful in that it allows applications to only ever reference standard portable Java EE names in both code and deployment descriptors. It also allows for the application to be unaware of network topology details/ This can even work with Java SE clients by using the little known EE Application Client feature. This feature allows you to run an extremely minimal AS server around your application, so that you can take advantage of certain core services such as naming and injection.
The Java EE platform specification defines the following JNDI contexts:
- java:comp - The namespace is scoped to the current component (i.e. EJB)
- java:module - Scoped to the current module
- java:app - Scoped to the current application
- java:global - Scoped to the application server
In addition to the standard namespaces, WildFly also provides the following two global namespaces:
|Only entries within the java:jboss/exported context are accessible over remote JNDI.|
|For web deployments java:comp is aliased to java:module, so EJB's deployed in a war do not have their own comp namespace.|
There are several methods that can be used to bind entries into JNDI in WildFly.
For Java EE applications the recommended way is to use a deployment descriptor to create the binding. For example the following web.xml binds the string "Hello World" to java:global/mystring and the string "Hello Module" to java:comp/env/hello (any non absolute JNDI name is relative to java:comp/env context).
For more details, see the Java EE Platform Specification.
Standard Java EE applications may use the standard JNDI API, included with Java SE, to bind entries in the global namespaces (the standard java:comp, java:module and java:app namespaces are read-only, as mandated by the Java EE Platform Specification).
|There is no need to unbind entries created programatically, since WildFly tracks which bindings belong to a deployment, and the bindings are automatically removed when the deployment is undeployed.|
With respect to code in WildFly Modules/Extensions, which is executed out of a Java EE application context, using the standard JNDI API may result in a UnsupportedOperationException if the target namespace uses a WritableServiceBasedNamingStore. To work around that, the bind() invocation needs to be wrapped using WildFly proprietary APIs:
|The ServiceTarget removes the bind when uninstalled, thus using one out of the module/extension domain usage should be avoided, unless entries are removed using unbind().|
It is also possible to bind to one of the three global namespaces using configuration in the naming subsystem. This can be done by either editing the standalone.xml/domain.xml file directly, or through the management API.
Four different types of bindings are supported:
- Simple - A primitive or java.net.URL entry (default is java.lang.String).
- Object Factory - This allows to to specify the javax.naming.spi.ObjectFactory that is used to create the looked up value.
- External Context - An external context to federate, such as an LDAP Directory Service
- Lookup - The allows to create JNDI aliases, when this entry is looked up it will lookup the target and return the result.
An example standalone.xml might look like:
The CLI may also be used to bind an entry. As an example:
|WildFly's Administrator Guide includes a section describing in detail the Naming subsystem configuration.|
For Java EE applications the recommended way to lookup a JNDI entry is to use @Resource injection:
Note that @Resource is more than a JNDI lookup, it also binds an entry in the component's JNDI environment. The new bind JNDI name is defined by @Resource's name attribute, which value, if unspecified, is the Java type concatenated with / and the field's name, for instance java.lang.String/myString. More, similar to when using deployment descriptors to bind JNDI entries. unless the name is an absolute JNDI name, it is considered relative to java:comp/env. For instance, with respect to the field named myString above, the @Resource's lookup attribute instructs WildFly to lookup the value in java:global/mystring, bind it in java:comp/env/java.lang.String/myString, and then inject such value into the field.
With respect to the field named hello, there is no lookup attribute value defined, so the responsibility to provide the entry's value is delegated to the deployment descriptor. Considering that the deployment descriptor was the web.xml previously shown, which defines an environment entry with same hello name, then WildFly inject the valued defined in the deployment descriptor into the field.
The executor field has no attributes specified, so the bind's name would default to java:comp/env/javax.enterprise.concurrent.ManagedExecutorService/executor, but there is no such entry in the deployment descriptor, and when that happens it's up to WildFly to provide a default value or null, depending on the field's Java type. In this particular case WildFly would inject the default instance of a managed executor service, the value in java:comp/DefaultManagedExecutorService, as mandated by the EE Concurrency Utilities 1.0 Specification (JSR 236).
Java EE applications may use, without any additional configuration needed, the standard JNDI API to lookup an entry from JNDI:
WildFly supports two different types of remote JNDI. The old jnp based JNDI implementation used in JBoss AS versions prior to 7.x is no longer supported.
The remote: protocol uses the WildFly remoting protocol to lookup items from the servers local JNDI. To use it, you must have the appropriate jars on the class path, if you are maven user can be done simply by adding the following to your pom.xml:
If you are not using maven a shaded jar that contains all required classes
can be found in the bin/client directory of WildFly's distribution.
The ejb: namespace is provided by the jboss-ejb-client library. This protocol allows you to look up EJB's, using their application name, module name, ejb name and interface type.
This is a client side JNDI implementation. Instead of looking up an EJB on the server the lookup name contains enough information for the client side library to generate a proxy with the EJB information. When you invoke a method on this proxy it will use the current EJB client context to perform the invocation. If the current context does not have a connection to a server with the specified EJB deployed then an error will occur. Using this protocol it is possible to look up EJB's that do not actually exist, and no error will be thrown until the proxy is actually used. The exception to this is stateful session beans, which need to connect to a server when they are created in order to create the session bean instance on the server.
Some examples are:
The first example is a lookup of a singleton, stateless or EJB 2.x home interface. This lookup will not hit the server, instead a proxy will be generated for the remote interface specified in the name. The second example is for a stateful session bean, in this case the JNDI lookup will hit the server, in order to tell the server to create the SFSB session.
For more details on how the server connections are configured, please see EJB invocations from a remote client using JNDI.