A general understanding of jndi:
jndi(java naming and directory Interface) It provides a set of interfaces that use naming and directory services. Users can use naming and directory services through it. Just like jdbc. jndi includes two parts: named service and directory service, where directory service contains directory object directory object, which contains several attribute objects. Provides many operations on properties.
Naming and Directory Services:
We have been using naming and directory services, such as the operating system's file system, which provides us with functions such as operations, queries, addition and deletion of files. The DNS service binds the URL and the IP address together. The most important function of naming and directory systems is to bind name and object. On the basis of it, it also provides more functions such as lookup and search. Moreover, the stored objects have a certain hierarchy. Using such a service, we can manage and operate objects more effectively.
The naming service maps a name to an object. RMI Registry and CORBA Naming Service are both naming services.
The directory service also stores objects, but the directory service recognizes the relevant properties of these objects. You can use project properties to search for directories.
In the early 1990s, the lightweight directory access protocol (LightWeightDiretoryAccessProtocol) was developed as a standard directory protocol, and JNDI was able to access LDAP.
j2se provides 5 extension packages for jndi:
context: context is a set of name-to-object bindings, which can be understood as a hierarchy or directory. It can also include the next layer of subContext. Getting initial context when using naming and directory services is the entry to the entire namespace operation. In the directory service is DirContext.
JNDI (Java Naming and Directory Interface) is an application-designed API that provides developers with a common and unified interface to find and access various named and directory services. JDBC is built on the abstraction layer.
The existing directories and services that JNDI can access are:
DNS, XNam, Novell directory service, LDAP (Lightweight Directory Access Protocol), CORBA object service, file system, Windows XP/2000/NT/Me/9x registry, RMI, DSML v1&v2, NIS.
Advantages of JNDI:
It contains a large number of naming and directory services, using a common interface to access different types of services; it can be connected to multiple naming or directory services at the same time; it establishes logical associations, allowing names to be associated with Java objects or resources without having to guide the physical ID of the objects or resources.
JNDI package:
JNDI vs. JDBC:
JNDI provides a unified way to find and access services on the network. By specifying a resource name that corresponds to a record in the database or naming service, it returns the information necessary for database connection establishment.
Code example:
try{Context cntxt = new InitialContext();DataSource ds = (DataSource) cntxt.lookup("jdbc/dpt");}catch(NamingException ne){...} JNDI and JMS:
Message communication is a method used by software components or applications to communicate. JMS is a JAVA technology that allows applications to create, send, receive, and read messages.
Code example:
try{Properties env = new Properties();InitialContext inictxt = new InitialContext(env);TopicConnectionFactory connFactory = (TopicConnectionFactory) inictxt.lookup("TTopicConnectionFactory");...}catch(NamingException ne){...} Visit specific directories: For example, a person is an object, and he has several attributes, such as the person's name, phone number, email address, postal code and other attributes. By getAttributes() method
Attribute attr = directory.getAttributes(personName).get("email");String email = (String)attr.get(); By using JNDI, letting customers use the object's name or attributes to find objects:
foxes = directory.search("o=Wiz,c=US", "sn=Fox", controls); Examples of finding printers by using JNDI to find objects such as printers and databases:
Printer printer = (Printer)namespace.lookup(printerName);printer.print(document);
Browse namespaces:
NamingEnumeration list = namespace.list("o=Widget, c=US"); while (list.hasMore()) {NameClassPair entry = (NameClassPair)list.next();display(entry.getName(), entry.getClassName());}Code example: Re-get the name, class name, and bound object.
NamingEnumeration namEnumList = ctxt.listBinding("cntxtName");...while ( namEnumList.hasMore() ) {Binding bnd = (Binding) namEnumList.next();String sObjName = bnd.getName();String sClassName = bnd.getClassName();SomeObject objLocal = (SomeObject) bnd.getObject();} Understanding the concepts of name services and directory services will help to better use JNDI. The Naming service name service defines how to associate a name with an object and how to find an object through a name. Typical examples are: DNS associates domain names with IP, and file systems associates file names with files. In name service, the main concepts:
- Names (Names), the code name of the actual object in the name system, such as file names, domain names, etc., it will be used to find the associated object. Different systems will have different naming specifications, such as the file system uses "/" to represent the hierarchy, while DNS uses ".".
- Bindings, the association of names and actual objects.
- References and Addresses. When an object cannot be stored directly in the name system, a reference must be used to find the actual object through reference. In the system, the content of the saved reference is called an address. Quotations have another use: in the name system, the concept of foreign keys in relational databases is lacking. By using references, it can be used as an alternative to foreign keys.
- Context, it is a name-object collection, providing the main operations to interact with the name system, such as search, binding, and de-binding. The relationship between the child context (subcontext) is similar to the relationship between directories and subdirectories in a file system. The child context is contained in a context and is associated with the child context through a name in the parent context.
- Naming Systems and Namespaces. The name system is a collection of the same type of context and provides name services. The name space is a collection of names in the name system, such as file names and directories of the file system.
Directory service directory service is an extension of the name service. In addition to associating names and objects, it also allows objects to contain attributes. Directory systems usually organize data in a hierarchy. The main concepts in directory services:
- Attributes, which belongs to a directory object, it is a (name, value) pair, and the attribute can have multiple values.
- Directories and Directory Services, directories are collections of directory objects; directory services provide directory-related services to create, delete and modify the properties of objects stored in the directory.
- Searches and Search Filters, the operation of obtaining directory objects is search; filters are objects similar to search conditions.
Basic use
² Registering a JNDI provider Before using JNDI, you need to obtain the JNDI provider and register it with the system. System properties related to JNDI are defined in javax.naming.Context, commonly used properties:
- java.naming.factory.initial, the class name used by the service provider to create the InitialContext.
- java.naming.provider.url, used to configure the initial url of InitialContext
- java.naming.factory.object, a class used to create name-to-object maps, used for NameClassPair and References.
- java.naming.factory.state, the class used to create jndi state. For directory services, it usually requires security settings and is usually used:
- java.naming.security.authentication, security type, three values: none, simple or strong.
- java.naming.security.principal, authentication information.
- java.naming.security.credentials, certificate information.
- java.naming.security.protocol, security protocol name.
Register with System.setProperty. If the program does not display the instructions, Java will look for the jdni.properties file in the classpath to complete the registration. jdni.properties example:
java.naming.factory.initial=com.codeline.db.MockInitialContextFactory
Connection Service
After registering, you can implement service connection. For name services, start with InitialContext, directory services use InitialDirContext. They implement Context and DirContext respectively. These two interfaces correspond to the interfaces of name services and directory services, and are also the two most important interfaces in JNDI.
Connect name service:
System.setProperty(Context.INITIAL_CONTEXT_FACTORY," com.sun.jndi.fscontext.FSContextFactory"); InitialContext ctx = new InitialContext();
Connect to directory services:
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://myserver.com/"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); //The username required to log in to ldap server is env.put(Context.SECURITY_PRINCIPAL, "ldapuser"); //Login to ldap The password required by the server is env.put(Context.SECURITY_CREDENTIALS, "mypassword"); InitialDirContext ctx = new InitialDirContext(env);
Multi-service provider: If the application contains multiple service providers, it is slightly different when connecting. Take name service as an example
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); env.put(Context.PROVIDER_URL, "rmi://myserver.com:1099"); //Use different constructors InitialContext ctx = new InitialContext(env);
Find objects
Whether it is a name service or a directory service, lookup is used to find objects. In addition to using String as a parameter, lookup can also use the Name interface as a parameter.
Greeter greeter = (Greeter)ctx.lookup("SayHello"); If you want to get all the object names in the context, use lis to return the NameClassPair list. NameClassPair contains object name and object class name. If you want to get the actual list of object instances, use listBindings, which returns the Binding list. Binding is a subclass of NameClassPair, which contains instances of objects.
- list
NamingEnumeration list = ctx.list("awt"); while (list.hasMore()) { NameClassPair nc = (NameClassPair)list.next(); System.out.println(nc); } - listBindings
NamingEnumeration bindings = ctx.listBindings("awt"); while (bindings.hasMore()) { Binding bd = (Binding)bindings.next(); System.out.println(bd.getName() + ": " + bd.getObject()); }
Object binding
- Add binding using bind
Fruit fruit = new Fruit("orange");ctx.bind("favorite", fruit); - Use rebind to modify binding
Fruit fruit = new Fruit("lemon");ctx.rebind("favorite", fruit); - Use unbind to remove bindings.
ctx.unbind("favorite");
Rename the object
Use rename to rename an object in the context
ctx.rename("report.txt", "old_report.txt");- The interfaces related to obtaining attribute attributes are Attribute and Attributes, both of which are in the javax.naming.directory package. You can get the object's attribute set through the getAttributes method of DirContext, then use the get method of Attributes to obtain the corresponding attributes, and finally you can get the attribute value through the get method of Attribute.
String dn = "uid=me, dc=mycompany, dc=com, ou=customer, o=ExampleApp"; Context user = (Context)ctx.lookup(dn); //Get all attributes Attributes attrs = user.getAttributes(""); Attribute test= attrs .get("test"); Object testValue= test.get();In the above example, all the attributes of user are obtained. In actual use, considering the impact of network bandwidth, you can set the list of attributes to be obtained:
String reqd_attrs = new String[] { "surname", "initials","title", "rfc822mailalias"}; Attributes attrs = user.getAttributes("", reqd_attrs);
Find and filter
Use the search method to complete.
public DirContext[] findUser(String initials,String Surname,String country,String phone) { //Construction conditions BasicAttributes search_attrs = new BasicAttributes(); search_attrs.put("initials", initials); search_attrs.put("sn", incident); search_attrs.put("c", country); if(phone != null) search_attrs.put("phonenumber", phone); NamingEnumeration results = initial_ctx.search("ou=Customer,o=ExampleApp", search_attrs); LinkedList found = new LinkedList(); while(results.hasMore()) { SearchResults sr = (SearchResults)results.next(); String name = sr.getName(); Object ctx = sr.getObject(); if((ctx == null) || !(ctx instanceof DirContext)) found.add(initial_ctx.lookup(name)); else found.add(ctx); } DirContext[] ret_val = new DirContext[found.size()]; found.toArray(ret_val); return ret_val; }
The main filtering methods of DirContext interface:
1. Use filter strings
String reqd_attrs = new String[] { "cn", "uid","rfc822mailalias" }; NamingEnumeration results = initial_ctx.search("ou=Customer, o=ExampleApp",search_attrs,reqd_attrs);
2. Use SearchControls to get more control
SearchControls ctrls = new SearchControls(); ctrls.setCountLimit(20); ctrls.setTimeLimit(5000); ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE); NamingEnumeration results = initial_ctx.search("cat=books,ou=Products, o=ExampleApp","title=*Java*",ctrls); Modify properties
It is done using the modifyAttributes methods of DirContext and InitialDirContext. The so-called modification process is actually to first construct the list of attributes to be modified and then submit using the above method. When a property contains multiple values, it is necessary to include the unmodified values of the property, otherwise the server will delete those values if they are no longer needed.
public void updateAddress(String dn,String address, String country, String phone) { BasicAttributes mod_attrs = new BasicAttributes(); if(address != null) mod_attrs.put("address", address); if(country != null) mod_attrs.put("c", country); if(phone != null) mod_attrs.put("phonenumber", phone); if(mod_attrs.size() != 0) initial_ctx.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, mod_attrs); } Using ModificationItem, you can also perform multiple different modification operations at once:
ModificationItem[] mod_items = new ModificationItems[2]; Attribute email = new BasicAttribute("rfc822mailalias", new_email); ModificationItem email_mod = new ModificationItem(DirContext.ADD_ATTRIBUTE, email); Attribute addr = new BasicAttribute("address", address); ModificationItem addr_mod = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, addr); mod_items[0] = email_mod; mod_items[1] = addr_mod; initial_ctx.modifyAttributes(dn, mod_items); Create a context
Use the createSubcontext method to complete.
BasicAttributes attrs = new BasicAttributes(); attrs.put("initials", initials); attrs.put("sn", incident); attrs.put("rfc822mailalias", email); if(address != null) attrs.put("address", address); if(country != null) attrs.put("c", country); if(phone != null) attrs.put("phonenumber", phone); initial_ctx.createSubcontext(dn, attrs);
Delete the context
Use destroySubcontext method to complete.
initial_ctx.destroySubcontext(dn);
Example
Here is another example.
Configure in tomcat's conf/server.xml:
<Context path="/jndi"> <Resource name="bean/MyBeanFactory" auth="Container" type="com.huawei.jndi.bean.MyBean" factory="org.apache.naming.factory.BeanFactory" bar="23"/> </Context>
A component is declared in tomcat above, and you can get this component in the code:
try { Context initContext = new InitialContext(); Context envCtx = (Context) initContext.lookup("java:comp/env"); MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory"); System.out.println(bean.getBar()); } catch (Exception e) { e.printStackTrace(); }Summary: Configure the jndi component in tomcat, and then get the equipped components in the code.
The JNDI implementation classes of each WEB container are different. For example, in JBOSS, the JNDI provision class is org.jnp.interfaces.NamingContextFactory, which is different from tomcat.
From this point of view, the role of JNDI is similar to that of spring's dependency injection. However, through JNDI, it is possible to obtain components across applications and even across domains. Components configured on server A can be obtained through JNDI on another server B.
Spring also provides encapsulation of jndi, which is more convenient to use. The following is an example.
<!-- JNDI template--> <bean id="jndiTemplate"> <property name="environment"> <props> <prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop> <prop key="java.naming.provider.url">10.137.96.212:18199</prop> <prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming</prop> </props> </property> </bean> <!-- Create a connection factory --> <bean id="jmsConnectionFactory"> <property name="jndiTemplate" ref="jndiTemplate" /> <property name="jndiName" value="TopicConnectionFactory" /> </bean>
First declare JndiTemplate, configure the target address and JNDI service provisioning classes. Then, through JndiObjectFactoryBean, you can easily obtain JNDI components and perform type conversion.