Singleton

The singleton pattern is a well-known pattern or, as some would argue, anti-pattern. Singletons have only one single instance per class within the whole application. The motivation for this pattern is the capability of storing states as well as being able to coordinate actions at a central place. Singletons definitely have their right to exist. If a certain state needs to be shared reliably among several consumers, a single point of entry is definitely the simplest solution.

However, there are some points to be aware of. Having a single point of responsibility also introduces concurrency that needs to be managed. Therefore, singletons need to be thread-safe. That said, we should keep in mind that singletons naturally don't scale, since there's only one instance. The more synchronization we introduce due to the contained data structure, the less our class will scale for concurrent access. However, depending on the use case, this might or might not be a issue.

The GoF book describes a static singleton instance that is managed in the singleton class. In Java EE the concept of singletons is directly built into EJBs with singleton session beans and CDIs with the application scope. These definitions will create one managed bean that is used in all clients.

The following demonstrates an example of a singleton EJB:

import javax.ejb.Singleton;

@Singleton
public class CarStorage {

    private final Map<String, Car> cars = new HashMap<>();

    public void store(Car car) {
        cars.put(car.getId(), car);
    }
}

There is some difference in whether we implement singletons using EJB singleton sessions beans or CDI application scoped beans.

By default, the container manages the concurrency of EJB singletons. This ensures that only one public business method is executed at a time. The behavior can be changed by providing the @Lock annotation which declares methods either as write-lock or read-lock, respectively, where the beans acts as a read-write lock. All EJB singleton business methods are implicitly write-locked. The following shows an example of using an EJB with container managed concurrency and lock annotations:

import javax.ejb.Lock;
import javax.ejb.LockType;

@Singleton
public class CarStorage {

    private final Map<String, Car> cars = new HashMap<>();

    @Lock
    public void store(Car car) {
        cars.put(car.getId(), car);
    }

    @Lock(LockType.READ)
    public Car retrieve(String id) {
        return cars.get(id);
    }
}

The concurrency can also switched off using bean managed concurrency. Then the bean will be called concurrently and the implementation itself has to ensure thread-safety. Using a thread-safe data structure, for example, doesn't require the EJB singleton to manage concurrent accesses. The business methods of the EJB instance will then be called in parallel, similarly to CDI application scoped beans:

import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class CarStorage {

    private final Map<String, Car> cars = new ConcurrentHashMap<>();

    public void store(Car car) {
        cars.put(car.getId(), car);
    }

    public Car retrieve(String id) {
        return cars.get(id);
    }
}

CDI application scoped beans don't restrict concurrent access and the implementation always has to deal with concurrency itself.

These solutions tackle situations where a singleton is required; for example, a state that needs to be shared in-memory in the whole application.

CDI application scoped beans or EJB singletons with bean managed concurrency and thread-safe data structures provide an application-wide, non-clustered in-memory cache that scale really well. If distribution is not required this is a simplest yet elegant solution.

Another widely used scenario for EJB singletons is the ability to invoke a single process at application startup. By declaring the @Startup annotation, the bean will be instantiated and prepared at application startup, invoking the @PostConstruct method. Startup processes can be defined for all EJBs, but using singletons we can realize processes that need to be set up exactly once.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.33.235