Singleton EJB tutorial
All of these approach worked, however they were not portable because they used JBoss annotations/configuration to do the trick.
Making an EJB as Singleton is pretty easy: just add the @java.ejb.Singleton annotation and that’s all.
Here’s an example:
@Singleton
@Startup
public class UserRegistry {
public ArrayList<String> listUsers;
@PostConstruct
public void init() {
listUsers = new ArrayList<String>();
listUsers.add("administrator");
}
public void addUser(String username) {
listUsers.add(username);
}
public void removeUser(String username) {
listUsers.remove(username);
}
public ArrayList<String> getListUsers() {
return listUsers;
}
}
In this example, the EJB exposes some methods to manage an in-memory cache based on an ArrayList.
Notice also the @Startup annotation which is not mandatory but can be used to signal to the container to invoke the @PostConstruct method just after the Bean has been created. So, if you need a proper Bean initialization, just add a @Startup annotation at Class level and a @PostConstruct at method level.
Testing the Singleton EJB is pretty simple, here’s a Servlet client:
@WebServlet("/servlet")
public class ServletClient extends HttpServlet {
@EJB UserRegistry ejb;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
ejb.addUser("frank");
out.println("List of users:")
ArrayList<String> list = ejb.getListUsers();
for (String s:list) {
out.println(s);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Please note that you won’t be able to look up remotely a Singleton EJB. If you need to access the Singleton EJB remotely you should include a wrapper Stateless Bean with a remote interface.
Managing concurrency in EJB singleton
Singleton session beans are designed for concurrent access, situations in which many clients need to access a single instance of a session bean at the same time.
There are two ways to manage concurrent access to Singleton EJBs. Let’s see them both.
Singleton Container-Managed Concurrency
If a singleton uses container-managed concurrency, the EJB container will manage access to the business methods of the singleton. This is the default if you don’t use any @ConcurrencyManagement annotation.
You can use the javax.ejb.Lock and javax.ejb.LockType annotation to specify the access level of the singleton’s business methods.
- Annotate a method with @Lock(LockType.READ) if the method can be concurrently accessed.
- Annotate a method with @Lock(LockType.WRITE) if the singleton session bean should be locked to other clients while a client is calling that method.
Typically, the @Lock(LockType.WRITE) annotation is used when clients are modifying the state of the singleton
The following example shows how to use the @ConcurrencyManagement, @Lock(LockType.READ), and @Lock(LockType.WRITE) annotations for a singleton that uses container-managed concurrency:
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Startup
public class UserRegistry {
public ArrayList<String> listUsers;
@PostConstruct
public void init() {
listUsers = new ArrayList<String>();
listUsers.add("administrator");
}
@Lock(LockType.WRITE)
@AccessTimeout(value=60, timeUnit=SECONDS)
public void addUser(String username) {
listUsers.add(username);
}
@Lock(LockType.WRITE)
@AccessTimeout(value=60, timeUnit=SECONDS)
public void removeUser(String username) {
listUsers.remove(username);
}
@Lock(LockType.READ)
public ArrayList<String> getListUsers() {
return listUsers;
}
}
You can specify how long the locks should be held by using the javax.ejb.AccessTimeout annotation.
The @AccessTimeout annotation can be applied to both @Lock(LockType.READ) and @Lock(LockType.WRITE) methods. .
The following excerpt shows how to apply a 1 minute timeout lock for some of your business methods:
@Lock(LockType.WRITE)
@AccessTimeout(value=60, timeUnit=SECONDS)
public void addUser(String username) {
listUsers.add(username);
}
@Lock(LockType.WRITE)
@AccessTimeout(value=60, timeUnit=SECONDS)
public void removeUser(String username) {
listUsers.remove(username);
}
Singleton Bean-Managed Concurrency
Singletons that use bean-managed concurrency allow full concurrent access to all the business and timeout methods in the singleton. The developer is now responsible for ensuring that the state of the singleton is synchronized across all clients. Typically, if you want to code EJB singletons with bean-managed concurrency, you should use synchronization primitives, such as synchronization and volatile, to prevent errors during concurrent access.
Add a @ConcurrencyManagement annotation with the type set to ConcurrencyManagementType.BEAN at the class level of the singleton to specify bean-managed concurrency:
@ConcurrencyManagement(BEAN)
@Singleton
public class UserRegistry { ... }
Handling failures in a Singleton Session Bean
If an EJB singleton encounters an error when initialized by the EJB container, that singleton instance will be destroyed and you won’t be able to access it.
However, once it is initialized, a singleton EJB, it is not destroyed if the singleton’s business or lifecycle methods cause System exceptions. This ensures that the same singleton instance is used throughout the application lifecycle.
Source code for this tutorial: https://github.com/fmarchioni/mastertheboss/tree/master/ejb/ejb-singleton
Recommended Articles
Exposing Stateless Session Bean as SOAP Web Service with JAX-WS
Learn how to expose a Stateless Session Bean as a SOAP web service endpoint in Java EE, including pros and cons compared to exposing POJOs.
Read Initialization Properties in EJB: A Simple Approach with Java and Singleton EJBs
Learn how to read properties from a file in an EJB-centric application using Java and Singleton EJBs. Get started with a simple example and understand the benefits of storing properties in a variable class.
CDI Tutorial: Choosing Between Different Bean Implementations with Java EE
Learn how to leverage CDI for dynamic bean selection in Java EE applications, including EJB implementations.
Mastering Bean Managed Transactions (BMT) in Java EE 3 Applications
Learn how to use Bean Managed Transactions (BMT) in EJB 3 applications for better transaction control and flexibility.