Vous êtes sur la page 1sur 15

Singleton Design Pattern

Java has several design patterns Singleton Pattern being the most commonly
used. Java Singleton pattern belongs to the family of design patterns, that
govern the instantiation process. This design pattern proposes that at
any time there can only be one instance of a singleton (object)
created by the JVM.

The class’s default constructor is made private, which prevents the direct
instantiation of the object by others (Other Classes). A static modifier is
applied to the instance method that returns the object as it then makes this
method a class level method that can be accessed without creating an object.

One such scenario where it might prove useful is when we develop the help
Module in a project. Java Help is an extensible, platform-independent help
system that enables authors and developers to incorporate online help into
applications.

Singletons can be used to create a Connection Pool. If programmers create a


new connection object in every class that requires it, then its clear waste of
resources. In this scenario by using a singleton connection class we can
maintain a single connection object which can be used throughout the
application.

Implementing Singleton Pattern

To implement this design pattern we need to consider the following 4 steps:


Step 1: Provide a default Private constructor

public class SingletonObjectDemo {

// Note that the constructor is private


private SingletonObjectDemo() {
// Optional Code
}
}

Step 2: Create a Method for getting the reference to the Singleton Object
public class SingletonObjectDemo {

private static SingletonObject singletonObject;


// Note that the constructor is private
private SingletonObjectDemo() {
// Optional Code
}
public static SingletonObjectDemo getSingletonObject() {
if (singletonObject == null) {
singletonObject = new SingletonObjectDemo();
}
return singletonObject;
}
}

We write a public static getter or access method to get the instance of the
Singleton Object at runtime. First time the object is created inside this
method as it is null. Subsequent calls to this method returns the same object
1
created as the object is globally declared (private) and the hence the same
referenced object is returned.

Step 3: Make the Access method Synchronized to prevent Thread Problems.

public static synchronized SingletonObjectDemo getSingletonObject()

It could happen that the access method may be called twice from 2 different
classes at the same time and hence more than one object being created. This
could violate the design patter principle. In order to prevent the simultaneous
invocation of the getter method by 2 threads or classes simultaneously we
add the synchronized keyword to the method declaration

Step 4: Override the Object clone method to prevent cloning

We can still be able to create a copy of the Object by cloning it using the
Object’s clone method. This can be done as shown below

SingletonObjectDemo clonedObject = (SingletonObjectDemo) obj.clone();

This again violates the Singleton Design Pattern's objective. So to deal with
this we need to override the Object’s clone method which throws a
CloneNotSupportedException exception.

public Object clone() throws CloneNotSupportedException {


throw new CloneNotSupportedException();
}

The below program shows the final Implementation of Singleton Design


Pattern in java, by using all the 4 steps mentioned above.

class SingletonClass {

private static SingletonClass singletonObject;


/** A private Constructor prevents any other class from instantiating.
*/
private SingletonClass() {
// Optional Code
}
public static synchronized SingletonClass getSingletonObject() {
if (singletonObject == null) {
singletonObject = new SingletonClass();
}
return singletonObject;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}

public class SingletonObjectDemo {

public static void main(String args[]) {


// SingletonClass obj = new SingletonClass();
//Compilation error not allowed
SingletonClass obj = SingletonClass.getSingletonObject();
2
// Your Business Logic
System.out.println("Singleton object obtained");
}
}

Another approach
We don't need to do a lazy initialization of the instance object or to check for
null in the get method. We can also make the singleton class final to avoid
sub classing that may cause other problems.

public class SingletonClass {

private static SingletonClass ourInstance = new SingletonClass();


public static SingletonClass getInstance() {
return singletonObj;
}
private SingletonClass() {
}
}

In Summary, the job of the Singleton class is to enforce the existence of a


maximum of one object of the same type at any given time. Depending on
your implementation, your class and all of its data might be garbage
collected. Hence we must ensure that at any point there must be a live
reference to the class when the application is running.

Service Locator

Brief Description

Enterprise applications require a way to look up the service objects that


provide access to distributed components. JavaTM 2 Platform, Enterprise
Edition (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. It also encapsulates any vendor-specific
features of the lookup process.

Detailed Description

See the Core J2EE Patterns

Detailed Example

The Java Pet Store sample application, v1.3.1 has two service locators: a
Web-tier class ServiceLocator , and an Enterprise JavaBeansTM (EJB) tier class,
also called ServiceLocator . Both classes manage lookup and caching of
enterprise bean home interfaces, JMS and database connection factories, and
environment entries within their respective tiers. The only difference between

3
them is that the Web-tier class is a singleton, and it caches the objects it
looks up. The EJB-tier class is not a singleton, and does not cache.
The following code discussion uses examples from the Web-tier
ServiceLocator :

• Clients use ServiceLocator to access services.

The sample application class AdminRequestBD is a business delegate


that uses the Web-tier ServiceLocator to access the order processing
center enterprise bean OPCAdminFacade . (See the Business Delegate
design pattern for a more detailed description of AdminRequestBD.)

Figure 1 is a structure diagram that demonstrates how


AdminRequestBD uses ServiceLocator to find the remote home
interface of the OPCAdminFacade enterprise bean. The ServiceLocator
returns a the remote enterprise bean interface OPCAdminFacadeHome,
by either retrieving it from the cache or looking it up using an internal
InitialContext instance. The client then uses the OPCAdminFacade to
find or create a remote component interface to an OPCAdminFacade

Figure 1. Structure diagram of ServiceLocator sample


code
In the following code excerpt, AdminRequestBD calls the
ServiceLocator static method getInstance to get the singleton instance
of the service locator, then calls getRemoteHome to get the remote
home interface of the OPCAdminFacade enterprise bean. Notice that
the caller must typecast the remote home interface to
OPCAdminFacadeHome because getRemoteHome returns type
EJBHome .

public class AdminRequestBD {


...
public AdminRequestBD() throws AdminBDException {
try {
OPCAdminFacadeHome home =
(OPCAdminFacadeHome)
ServiceLocator.getInstance().getRemoteHome(OPC_ADMIN_NAM
E, OPCAdminFacadeHome.class);
opcAdminEJB = home.create();
} catch (ServiceLocatorException sle) {

4
...
}
}
The service locator greatly simplifies the lookup of the enterprise bean
home interface. The singleton and caching strategies (discussed
below) also improve performance, because they avoid constructing
unnecessary InitialContext and enterprise bean home interfaces.

• Public methods look up distributed resources.

The public methods of the service locator look up distributed resources


by their JNDI names. There are methods that find and return enterprise
bean local home interfaces, JDBCTM data sources, JMS queues and
topics, and JMS queue and topic connection factories. There are also
convenience methods that look up and perform type conversions on
environment entries.

As an example, method getLocalHome (for finding enterprise bean


local home interfaces) appears below. Each method that locates a
particular type of resource returns either a cached reference to the
requested resource, or uses JNDI to find the resource, placing a
reference in the cache before returning it.

// Enterprise bean lookups


public EJBLocalHome getLocalHome(String jndiHomeName)
throws ServiceLocatorException {
EJBLocalHome home = null;
try {
if (cache.containsKey(jndiHomeName)) {
home = (EJBLocalHome) cache.get(jndiHomeName);
} else {
home = (EJBLocalHome) ic.lookup(jndiHomeName);
cache.put(jndiHomeName, home);
}
} catch (NamingException ne) {
throw new ServiceLocatorException(ne);
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
return home;
}

Methods that return enterprise bean home interface references are


only type-safe to the platform interface level; for example,
getLocalHome returns a EJBLocalHome, but the client must typecast
the result.
Method getRemoteHome is similar to getLocalHome, except that it
returns an enterprise bean remote, instead of local, home interface. It
also requires a reference to a class object for the specific remote home
interface, because remote home lookups use method
PortableRemoteObject.narrow to perform the type conversion from the
object returned from the JNDI lookup to the actual home interface type.
The client that calls getRemoteHome must still typecast the result to
the remote home interface type, as shown in the first example above.
5
public EJBHome getRemoteHome(String jndiHomeName, Class
className)
throws ServiceLocatorException {
EJBHome home = null;
try {
if (cache.containsKey(jndiHomeName)) {
home = (EJBHome) cache.get(jndiHomeName);
} else {
Object objref = ic.lookup(jndiHomeName);
Object obj = PortableRemoteObject.narrow(objref,
className);
home = (EJBHome)obj;
cache.put(jndiHomeName, home);
}
} catch (NamingException ne) {
throw new ServiceLocatorException(ne);
} catch (Exception e) {
throw new ServiceLocatorException(e);
}

return home;
}
As mentioned above, the service locator returns JMS resources, JDBC
data sources, and performs type conversion on values in environment
entries. The table below summarizes the names and return types of
these methods.
Table 1. Additional ServiceLocator methods
Resour
Method Return
ce
Name Type
Type
getQueueConnection QueueConnectionF
JMS
Factory actory
getQueue Queue JMS
getTopicConnectionF TopicConnectionFa
JMS
actory ctory
getTopic Topic JMS
getDataSource DataSource JDBC
env-
getUrl URL
entry
env-
getBoolean boolean
entry
env-
getString String
entry

• Improving performance with the Singleton pattern and caching.

The Singleton pattern [ GHJV95 ] 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.

6
The Singleton pattern improves performance because it eliminates
unnecessary construction of ServiceLocator objects, JNDI InitialContext
objects, and enables caching (see below).

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.

The code excerpt below demonstrates how the ServiceLocator


improves performance with the Singleton pattern and an object cache.

public class ServiceLocator {

private InitialContext ic;


private Map cache;

private static ServiceLocator me;

static {
try {
me = new ServiceLocator();
} catch(ServiceLocatorException se) {
System.err.println(se);
se.printStackTrace(System.err);
}
}
private ServiceLocator() throws ServiceLocatorException {
try {
ic = new InitialContext();
cache = Collections.synchronizedMap(new HashMap());
} catch (NamingException ne) {
throw new ServiceLocatorException(ne);
}
}

static public ServiceLocator getInstance() {


return me;
}
A private class variable me contains a reference to the only instance of the
ServiceLocator class. It is constructed when the class is initialized in the static
initialization block shown. The constructor initializes the instance by creating
the JNDI InitialContext and the HashMap that is used a cache. Note that the
no-argument constructor is private: only class ServiceLocator can construct a
ServiceLocator. Because only the static initialization block creates the
instance, there can be only one instance per class loader. Classes that use
service locator access the singleton ServiceLocator instance by calling public
method getInstance. Each object looked up has a JNDI name which, being
unique, can be used as a cache HashMap key for the object. 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.

Problem:

J2EE specification mandates the usage of JNDI (Java Naming and Directory
Interface) to access different resources/services. J2EE compatible server
7
binds these resources/services to the JNDI server so that the clients can
lookup those resources/services through JNDI lookup process from anywhere
in the network. The resources/services can be
1. EJBHome objects 2. DataSource objects 3. JMS
ConnectionFactory 4. JMS Topic/Queue etc.

EJB Client needs to initially get EJBHome object from JNDI to manage life cycle
of EJBObjects. JMS clients need to get ConnectionFactory and Topic/Queue
from JNDI for processing messages. JDBC clients need to get DataSource
object in order to get database connection. All these services need to bind to
the JNDI services and the clients need to lookup JNDI to get those services.
Clients have to go through JNDI lookup process every time to work with these
services. JNDI lookup process is expensive because clients need to get
network connection to the JNDI server if the JNDI server is located on a
different machine and need to go through lookup process every time, this is
redundant and expensive.

The figure below shows the client's JNDI lookup process.

Solution through Service Locator Pattern:


The solution for the redundant and expensive JNDI lookup process problem is
to cache those service objects when the client performs JNDI lookup first time
and reuse that service object from the cache second time onwards for other
clients. This technique maintains a cache of service objects and looks up the
JNDI only first time for a service object. This technique reduces redundant
and expensive JNDI lookup process thus increasing performance significantly.
Service Locator Pattern implements this technique by having a class to cache
service objects, methods for JNDI lookup and methods for getting service
objects from the cache.
The figure below shows the ServiceLocator class intercepting the client
request and accessing JNDI once and only once for a service object.

8
Here the clients call ServiceLocator class to get a service object rather than
calling JNDI directly. ServiceLocator acts as interceptor between client
and JNDI. For source code and different flavors of implementation of this
Pattern, see the following links.

Business Delegate

Brief Description

In distributed applications, lookup and exception handling for remote


business components can be complex. When applications use business
components directly, application code must change to reflect changes in
business component APIs.
These problems can be solved by introducing an intermediate class called a
business delegate, which decouples business components from the code that
uses them. The Business Delegate pattern manages the complexity of
distributed component lookup and exception handling, and may adapt the
business component interface to a simpler interface for use by views.

Detailed Description

See the Core J2EETM Patterns

Detailed Example

Sample application business delegate class AdminRequestBD handles


distributed lookup and catches and adapts exceptions in the sample
application order processing center (OPC).

• The AdminRequestBD business delegate manages distributed


component lookup and handles exceptions.

The structure diagram in Figure 1 shows the ApplRequestProcessor


servlet using AdminRequestBD to find and use distributed business
components.

9
Figure 1. AdminRequestBD locates and adapts other
business components

The code sample below shows the constructor for AdminRequestBD. It


uses class ServiceLocator to acquire the remote home interface of
session facade OPCAdminFacade . (See the Service Locator and
Session Facade design patterns.) It uses the remote home interface to
create a OPCAdminFacade remote component interface, which it
maintains in a private field. The block that locates and creates the
enterprise bean reference catches exceptions related to finding the
home interface and to creating the component interface. Any
exception that occurs is then wrapped in an AdminBDException , which
effectively hides the implementation details of the business delegate
from its clients.

public AdminRequestBD() throws AdminBDException {


try {
OPCAdminFacadeHome home = (OPCAdminFacadeHome)
ServiceLocator.getInstance().getRemoteHome(OPC_ADMIN_NAME,
OPCAdminFacadeHome.class);
opcAdminEJB = home.create();
} catch (ServiceLocatorException sle) {
throw new AdminBDException(sle.getMessage());
} catch (CreateException ce) {
throw new AdminBDException(ce.getMessage());
} catch (RemoteException re) {
throw new AdminBDException(re.getMessage());
}
}

• The OPC request processor uses AdminRequestBD for simple access to


business components components.

OPC servlet class ApplRequestProcessor receives service requests from


the admin client in the form of XML messages transmitted using HTTP.
One of these request is for statistics about orders that have a given
status.

Method ApplRequestProcessor.getOrders receives part of an XML DOM


tree representing a Web service request. It extracts the status code
from the document and uses AdminRequestBD.getOrdersByStatus to
retrieve a list of order information. The interface to that list is transfer
object interface OrdersTO . (See the Transfer Object pattern.) The code
10
in the request processor that retrieves the order information appears in
the following code sample.

public class ApplRequestProcessor extends HttpServlet {


...
String getOrders(Element root) {
try {
AdminRequestBD bd = new AdminRequestBD();
NodeList nl = root.getElementsByTagName("Status");
String status = getValue(nl.item(0));
OrdersTO orders = bd.getOrdersByStatus(status);
...
}
Because it has already created the reference to an
OPCAdminFacadeEJB, the AdminRequestBD object can simply forward
the call to the enterprise bean's method getOrdersByStatus, as follows:

public class AdminRequestBD {


...
public OrdersTO getOrdersByStatus(String status)
throws AdminBDException {

try {
return opcAdminEJB.getOrdersByStatus(status);
} catch (RemoteException re) {
throw new AdminBDException(re.getMessage());
} catch (OPCAdminFacadeException oafee) {
throw new AdminBDException(oafee.getMessage());
}
}
...
}
Notice again that the method catches any exceptions that the
enterprise bean may throw and re-throws an exception type that is
specific to the business delegate's interface. This hides the business
delegate's implementation details from the client.

Session Façade

A commonly used J2EE pattern for EJBs is called the Session Facade pattern.
In this pattern, a stateless session bean is used as a facade to hide access to
one or more entity beans. Remote clients interact only with the session bean
and never directly with the entity beans

 The first important benefit of the Session Facade pattern is that the
client has a simpler interface and doesn't need to know about the
details of which entity beans and which methods to use. In my
analogy, the session bean is like the general contractor and the entity
beans are the subcontractors.
 The Session Facade pattern improves performance as only the calls
between the client and the session bean go across the network, while
calls from the session bean to the entity beans are local to the EJB
container.
 Performance can be further enhanced through the use of local
interfaces, introduced as part of the EJB specification version 2.0. Local

11
interfaces provide support for "lightweight" access from within the EJB
container, avoiding the overhead associated with a remote interface.
 A third benefit of the Session Facade pattern relates to transactions.
With container-managed transactions, the container begins a
transaction when a method starts to execute and ends the transaction
when the method returns. By enclosing the entity beans calls in the
session bean method, the database operations are automatically
grouped together as a transactional unit. To ensure that they
participate in the same transaction, the entity bean methods should be
assigned the "Required" transaction attribute in ejb-jar.xml

Problem:

EJB clients (swing, servlets, jsps etc) can access entity beans directly. If EJB
clients access entity beans directly over the network, it takes more network
calls and imposes network overhead. The following figure illustrates this
process:

12
Here in the above figure, the servlet calls multiple entity beans directly to
accomplish a business process, thereby increasing the number of network
calls.
Solution through Session Facade Pattern:
The solution for avoiding number of network calls due to directly accessing
multiple entity beans is to wrap entity beans with session bean (Facade). The
EJB client accesses session bean (Facade) instead of entity beans through
coarse grained method call to accomplish a business process.
The following figure illustrates how the session facade (session bean) acts as
an interceptor between client and entity beans:

Here the client makes only one coarse grained method call to session bean
(facade) to process a business method instead of placing fine grained calls to
entity beans. The session bean in turn calls entity beans to process client
request. Entity beans can be made local by implementing EJB2.0 local
interfaces to reduce remote overhead between session facade and entity
beans. Therefore the session facade reduces the network traffic and
increases performance.

Value Object

Problem:

When a client calls a remote method there will be process of marshalling,


network calls and unmarshalling involved for the remote method invocation.
If you choose fine grained approach when calling methods remotely, there
will be a significant network overhead involved. For example if you call fine
grained method like this, remoteObject.getName();
remoteObject.getCity(); remoteObject.getState();
emoteObject.getZipCode();

Here, there are four network calls from client to the remote object because
every method call is remote method call. The following figure illustrates the
fine grained approach when calling methods remotely :

13
As seen in the above figure the fine grained approach imposes a overhead on
the network due to the number of calls.
Solution through Value Object Pattern:
The solution for avoiding many network calls due to fine grained method calls
is to use coarse grained approach. For example :
// create an Value Object and fill that object locally
PersonInfo person = new PersonInfo();
person.setName("Ravi");
person.setCity("Austin");
person.setState("TX");
person.zipCode("78749");
// send Value Object through network
remoteObject.getPersonInfo(person);
Here, there is only one network call instead of three network calls and
PersonInfo object is a Value Object. The following figure illustrates the coarse
grained approach that is passing a Value Object through network.

14
Value Object is an object that is passed over the network rather than passing
each attributes separately thus increasing performance by reducing network
calls.

Key Points

1. to Use ServiceLocator/EJBHomeFactory Pattern to reduce expensive


JNDI lookup process.
2. Use SessionFacade Pattern to avoid direct client access to Entity beans
thus reducing network calls.
3. Use MessageFacade/ServiceActivator Pattern to avoid large method
execution process.
4. Use ValueObject Pattern to avoid fine grained method calls over
network.
5. Use ValueObjectFactory/ValueObjectAssembler Pattern to avoid
multiple network calls for a single client request.
6. Use ValueListHandler Pattern to avoid using Entity beans and send data
iteratively to the client.
7. Use CompositeEntity Pattern avoid inter Entity bean overhead.

15