I have a REST interface for development purposes which sports a stateless EJB. It in turn injects another stateless EJB. It was my understanding that a stateless EJB is destroyed instead of passivated and reconstructed every time an instance is needed.
Using this logic I added a #PostConstruct (to both the REST and the other stateless ejb) but both are only called once (deduced from logging). Repeated calls to the REST layer will reuse the same bean (and its state!) instead of creating a new one.
What are the possible reasons that the stateless beans are not getting destroyed? Or have I misinterpreted the lifecycle of a stateless ejb?
EDIT: the "state" I'm referring to is a temporary cache the bean constructs to speed up execution. Perhaps a poor choice of words :)
EDIT2: some skeleton code:
import javax.ejb.Stateless;
import javax.ejb.EJB;
import javax.ws.rs.Path;
#Path("tools")
#Stateless
public class RESTTools {
#EJB
private CatalogueLocal catalogue;
#PostConstruct
public void initialize() {
logger.debug("Initializing REST client");
}
}
#Stateless
#Local(CatalogueLocal.class)
#TransactionManagement(TransactionManagementType.BEAN)
public class Catalogue {
#PostConstruct
public void initialize() {
logger.debug("Initializing catalogue");
}
}
I believe you have misinterpretted the lifecycle.
Stateless beans are instantiated as needed and are activated from an instance pool by the container.
Related
I'm using a Java EE 7 + GlassFish and need to perform some operation against a number of JPA entities from a stateless bean.
#Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
///do some work against entity
}
}
}
This JobRunner bean is injected into the servlet and I invoke do() method from the web UI.
The issue is that all entities are being changed within one transaction so if one fails everything is rolled back what is not desirable. Is there a way to start and close a new transaction for each entity (i.e. for each iteration of the loop)?
I can write an external client and make a loop there calling a stateless bean for each entity but it's not something that completely works for me as I prefer to keep an app monolithic. Can I somehow manage transactions form inside a container?
Maybe JMS helps? If I implement a doer as message listener and will be sending a message for each entity, will it start a new transaction for each one?
#Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
sendMessageToRealDoer(entity);
}
}
}
Create another bean, specifying #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW), at method or bean level:
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
#Stateless
public class JobWork {
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doWork(Entity entity) {
// do what you would do in the loop with the Entity
// this runs in a new transaction
}
}
I wish I could tell you that you only need to annotate a method of the same bean (JobRunner) and simply call it. This is not possible (EDIT)without workarounds - check comment from Steve C(/EDIT) because when calling methods of this object in EJBs and CDI beans the interceptors do not get called. Transactions are implemented with interceptors in both cases.
Some notes:
If the total duration of the operations in the loop is expected to be long, you will get a timeout in the outer transaction, that is implicitly started for the JobRunner stateless EJB. You will want to take measure that no "outer" transaction is started.
Sending the data to a queue will work too; but queues will process them asynchronously, meaning that the execution will return to the servlet calling JobRunner.do() most probably before all items have been processed.
I am trying to use and understand CDI, when I use #Inject in a simple pojo class, it throws me NPE.
example
Greeting.java
public Class Greeting {
public String greet() {
System.out.println("Hello");
}
}
Test.java
import javax.inject.Inject;
public class Test {
#Inject
private Greeting greeting;
public void testGreet() {
greeting.testGreet();
}
}
When I call testGreet() it throws NPE, why is the greeting instance null. Does #Inject way of adding dependency only be used in container managed bean?
Note: jar is not the problem here.
TL;DR:
#Inject-annotated fields are only populated for container-instantiated beans.
Long version:
The CDI container provides you a lot of utilities for easily injecting dependencies to your beans, but it doesn't work by magic. The container can only populate the annotated fields of a client bean if the client bean itself was instantiated by the container. When the container is instantiating the object the sequence of events is as follows:
Your bean's constructor is called.
#Inject-annotated fields (and some other
annotations, #PersistenceContext and #EJB for instance) are
populated.
#PostConstruct-annotated no-args method is called.
Your bean is finished.
You're facing a classic bootstrapping problem, how to move from non-container-managed code into container-managed code. Your options are:
Get access to an instance of BeanManager from your JavaEE container via JNDI lookup. This is technical and a bit clumsy.
Use a CDI extension library such as Apache DeltaSpike. (Example: BeanProvider.getContextualReference(Test.class, false);)
Modify your application to start in a situation where you can inject your Test class rather than calling new Test();. This can be done for example by setting up a startup singleton ejb, which calls your test in it's #PostConstruct-annotated initialisation.
Hope this helps.
You need a JavaEE container, and than you need to define Greeting and Test as managed beans. After that you can inject one in another.
Try to take a look at:
https://docs.oracle.com/javaee/6/tutorial/doc/girch.html
Your class should be implemented from Serializable for being injectable as a "CDI Bean"
I have the following setup:
#Singleton
#Startup
#DependsOn(value="DataSourceHandler")
public class TimerTask {
#EJB(name = "DataSourceHandler")
DataSourceHandler dataSourceHandler;
}
#Stateless(name = "DataSourceHandler")
public class DataSourceHandler {
... database operations
}
The timertask runs once every 30 minutes and performs database operations with the help of the DataSourceHandler EJB.
The problem here is that I'm unable to inject the EJB into the Singleton Timertask, because a singleton can only depend on other singletons. The solutions proposed in other questions don't work for me however:
I can't make the DataSourceHandler a Singleton because it is also used in other parts of the application and not multithreading-save.
I can't remove the Singleton from the TimerTask because it is required for the #Startup annotation
How can I inject a stateless into a singleton?
You do not need a dependsOn annoatation here.
#dependson is used for the below case:
Used to express an initialization dependency between singleton
components.
Since DataSourceHandler is an EJB, it will be instantiated by the container at the moment your singleton injects this EJB.
I have a class as below:
public class UserAuthenticator {
private static UserAuthenticator authenticator =
#Inject
private UserRepository userRepository;
#PostConstruct
public void init() {
List<User> allUsers = userRepository.findAll();
for (User user : allUsers) {
users.put(user.getEmail(), user.getPassword());
serviceKeys.put(user.getServiceKey(), user.getEmail());
}
}
public static UserAuthenticator getInstance() {
if (authenticator == null) {
authenticator = new UserAuthenticator();
}
return authenticator;
}
}
When I call
UserAuthenticator authenticator = UserAuthenticator.getInstance();
init() method isn't called and userRepository is null
My web application run in JBOSS EAP 6.3.
How is this caused and how can I solve it?
In a Java EE application, don't think in singletons. That's only recipe for trouble and confusion. Instead, think in "just create one". Tell the Java EE container to just create only one instance of the specified class, application wide, and obtain the instance via the facility offered by the Java EE container. Your concrete problem is caused because you're manually creating an instance of the class using new operator without manually performing the injection and post construct call like as the technical correct but conceptually wrong example below:
authenticator = new UserAuthenticator();
authenticator.userRepository = new UserRepository();
authenticator.init();
In other words, you incorrectly expected that the new operator magically recognizes the bean management and dependency injection related annotations.
The right approach depends on the one you'd like to point out as the responsible for creating and managing the instance of the specified class. If it's CDI, then just tell it to create only one managed bean instance of the backing bean class, application wide, using #Named #ApplicationScoped.
import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;
#Named
#ApplicationScoped
public class UserAuthenticator {}
It will be created just once and be available via #Inject as below in any other Java EE managed artifact (read: in any other class annotated with #Named, #Stateless, #ManagedBean, #WebServlet, #WebListener, #WebFilter, #Path, etc..):
#Inject
private UserAuthenticator userAuthenticator;
If you're absolutely positive that you need a static method to grab the current CDI managed bean instance of a given backing class, then you should be obtaining it via BeanManager as below instead of manually constructing the instance (assuming Java EE 7 / CDI 1.1 available):
#SuppressWarnings("unchecked")
public static <T> T getCurrentInstance(Class<T> beanClass) {
BeanManager beanManager = CDI.current().getBeanManager();
Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(beanClass));
return (T) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
}
Usage:
UserAuthenticator userAuthenticator = YourCDIUtil.getCurrentInstance(UserAuthenticator.class);
// ...
See also:
Java singleton class vs JSF application scoped managed bean - differences?
Java EE 6 and Singletons
Well i think you shouldn't explictly call UserAuthenticator.getInstance() but to define the UserAuthenticator for example as #ApplicationScoped and get the instance via DI provided by your app server (#Inject).
UserAuthenticator should be then initialized properly.
The #PostConstruct method will not be invoked until you do some action on that class (ex: call some methods
if I understand it right a #Stateful bean saves the state. If the client does a request again it comes back to the same instance. So it's possible to save class-attributes, what's not possible in #Stateless. In an other thread here someone wrote "it's like a classical java instance, every injection gets it's own instance of this bean".
But I don't understand how the mapping of the request to the #Stateful bean works - what is to do that it works? This question goes out for two cases:
I call #Stateful by a webservice by the client software. Is it an ID I have to send with it? But what is the ID and how do the container knows that this is the identify-attribut and routes it to the right #Stateful bean?
I call #Stateful out of an #Stateless bean. As example if the client first calls a #Stateless bean and is redirect to his #Stateful bean.
This question is not for the technical process of the container / server-software, it's for the specific doing at the development. Thank you for your support.
Greetings
That's unfortunately not the way web services work. The stateful bean is only stateful for the stateless bean. And not for a client. And that's very dangerous for several reasons:
-The stateless bean saves state of a call in its stateful reference. But the next call of the stateless bean can be happen in another context/by another client.
-The stateful bean can be destroyed by the container while the stateless is still alive/in the pool.
You can use stateful beans with remote-calls or in web applications but not in the context of webservices.
A webservice is per definition without any application state. The Java EE-Servlet listens for the requests and call one stateless bean implementation from a pool of instances.
If you really want to implement stateful web services, you must do it on your own. The following example will work in a Java EE 6-container:
/// Client depended values(your statefull bean)
public class SessionValues {
private final List<String> values = new ArrayList<String>();
public void addValue(String s){
values.add(s);
}
public List<String> loadValues(){
return Collections.unmodifiableList(values);
}
}
You can store the sessions in a singleton(your own pool)
#Singleton
#Startup
public class StatefullSingleton {
private final Map<String, SessionValues> sessions = new Hashtable<String, SessionValues>();
#Lock(LockType.READ)
public void addValue(String sessionId, String value) {
if (!sessions.containsKey(sessionId))
sessions.put(sessionId, new SessionValues());
SessionValues p = sessions.get(sessionId);
p.addValue(value);
}
#Lock(LockType.READ)
public List<String> loadValues(String sessionId) {
if (sessions.containsKey(sessionId))
return sessions.get(sessionId).loadValues();
else
return new ArrayList<String>();
}
}
and inject the singleton in the stateless webservice beans(the pool, the singleton and the calls of the singleton are managed by the Java EE-Container):
#Stateless
#WebService
public class WebserviceBean {
#Inject
private StatefullSingleton ejb;
public void addvalue(String sessionId, String value) {
ejb.addValue(sessionId, value);
}
public List<String> loadValues(String sessionId) {
return ejb.loadValues(sessionId);
}
}
The example above is only a pattern. You must be very carefully with the session-id and the multithreading if you want to implement it in production.
Edit: remove the unnecessary #localBean