Service Locator :
Enterprise applications require a way to look up the service objects that provide access to distributed components. J2EE applications use Java Naming and Directory Interface (JNDI) to look up enterprise bean home interfaces, Java Message Service (JMS) components, data sources, connections, and connection factories. Repetitious lookup code makes code difficult to read and maintain. Furthermore, unnecessary JNDI initial context creation and service object lookups can can cause performance problems.
The Service Locator pattern centralizes distributed service object lookups, provides a centralized point of control, and may act as a cache that eliminates redundant lookups.
Improving performance with the Singleton pattern and caching.
The Singleton pattern ensures that only a single instance of a class exists in an application. The meaning of the term “singleton” is not always clear in a distributed environment; in ServiceLocator it means that only one instance of the class exists per class loader.
The Singleton pattern improves performance because it eliminates unnecessary construction of ServiceLocator objects, JNDI InitialContext objects, and enables caching .
The Web-tier service locator also improves performance by caching the objects it finds. The cache lookup ensures that a JNDI lookup only occurs once for each name. Subsequent lookups come from the cache, which is typically much faster than a JNDI lookup.
Let’s see the below example to understand it clearly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; public class ServiceLocator { private InitialContext initialContext; private Map cache; private static ServiceLocator instance; static{instance = newServiceLocator();} private ServiceLocator(){ try { initialContext = new InitialContext(); cache = Collections.synchronizedMap(new HashMap()); } catch (NamingException ne) { ne.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static ServiceLocator getInstance() { return instance; } public DataSource getDataSource(String dataSourceName) { DataSource dataSource = null; try { if (cache.containsKey(dataSourceName)) { dataSource = (DataSource) cache.get(dataSourceName); } else { dataSource = (DataSource) initialContext.lookup(dataSourceName); cache.put(dataSourceName, dataSource); } } catch (NamingException nex) { nex.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } return dataSource; } } |
Components of the above class:
We have a static block for creating instance of the class which get executed while loading the class,
Note that the no-argument constructor is private
: only class ServiceLocator
can construct a ServiceLocator
. That also create the initialContext object and initialize a Map to store the Data source object.
We have getInstance method , which returns the ServiceLocator instance
Finally, We have getDataSource method which accepts the String parameter dataSourceName
In this method , we will check whether the requested datasource name present in the Map or not, If not this method will create the DataSource object and put it in the map , datasourceName as key for future reference and retun that DataSource object. Hence if there is any request in future with the same datasource name, the DataSource object will be taken from the Map and serve the client.
Note also that the HashMap
used as a cache is synchronized so that it may be safely accessed from multiple threads that share the singleton instance.
Getting datasource object from ServiceLocator:
String dataSourceName =”java:comp/env/devDS”;
DataSource ds=ServiceLocator.getInstance().getDataSource(dataSourceName);
Recommended Books
Leave a Reply