After constructing the bean, I want to retrieve data from the database, using the EntityManager. It is not possible in the constructor, because the EntityManager is injected after the constructor is called. So I tried to do it in a method annotated with #PostConstruct. According to the API, a PostConstruct Methods gets called after all injection are done. Executing the query works, but it always returns an empty list. If I use the same query in an other method, it returns the correct result. Does anybody know, why it does not work in the PostConstruct method?
#Stateful(mappedName = "price")
#Singleton
#Startup
public class PriceManagementBean implements PriceManagement {
#PersistenceContext
private EntityManager em;
private List<PriceStep> priceSteps = Collections.synchronizedList(new ArrayList<PriceStep>());
public PriceManagementBean(){
}
#PostConstruct
public void init(){
javax.persistence.Query query = em.createQuery("SELECT ps FROM PriceStep ps");
List<PriceStep> res = query.getResultList();
.....
}
}
Does anybody know, why it does not work in the PostConstruct method?
Reason 1
You cannot create a bean that is at the same time #Stateful and #Singleton(Well you can but it will make no sense since Singletons are also Stateful), that is one of the reasons you are having trouble. There is no exceptions, but there is a conflict in there, you need to fix that first.
Just remember:
A Singleton bean is a bean that mantains its state. There is only one instance of a Singleton in an application and it is shared among all the users of the app. Also since it is a shared(maybe better say concurrent) bean, there is need to implement some kind of locking mechanism using the #Lock annotation.
A Stateful bean is a bean that mantains each state after a transaction. When working with
Stateful beans each user gets a copy of the bean which will last as long as the session - lasts or until a method annotated with #Remove is called
Reason 2
Even if it works, you will be unable to access the results, because you are storing them in an object called res which is only accessible from inside the method init(). I suppose you would like to assign that returned value to the variable priceSteps.
Anyway there are many things wrong in your code, for not saying everything. I don't know what are your system requirements, but here i would give you a simple solution that will allow you to access the database:
I suppose you are trying to in some way return the data in the life cycle of the bean because you want to avoid sending queries again and again if the bean is #Stateful.
The thing is, you don't have to do that, you can still make your bean #Stateless and avoid stressing your database with many queries.
What you need to do is create a #NamedQuery.
So annotate your entity PriceStep with #NamedQuery and there enter the query string you wrote. In this link you will find information about how to use #NamedQueries:
http://docs.oracle.com/cd/B31017_01/web.1013/b28221/ent30qry001.htm
The next thing i would suggest you is to annotate your class PriceManagementBean as *#Stateless*. Don't worry if in each request a new entityManager is created, that does not stress the database at all, because it interacts with the domain model.
You don't need #PostConstruct, you just call your #NamedQuery whenever you need it and that's it. The app server will cache it and give it back to each user that requires it without interacting with the database all time.
Here a codesnipet:
#Entity
#NamedQuery(
name="allPriceSteps",
queryString="SELECT ps FROM PriceStep ps"
)
public class PriceStep implements Serializable {
...
}
Now the bean:
#Stateless
public class PriceManagementBean implements PriceManagement {
#PersistenceContext
private EntityManager em;
public List<PriceStep> getAllPriceSteps() {
Query query = em.createNamedQuery("allPriceSteps");
return query.getResultList();
}
}
I hope this is useful. If you give more information about your system requirements we could give you advice on a best practice.
Based on your requirement please try the following
Remove #Stateful [CAN'T use both at a time]
#Startup will initialize singleton bean during APPLICATION INIT [Please note the application was NOT fully initialized]. This might caused some issue in loading EntityManager and i assume the EntityManager bridge was not completely initialized. Try to call the init after complete application startup [i.e.,] Remove #Startup
Related
I'm working on a legacy codebase and saw something unsettling in our custom repositories. EntityManager is autowired into the repos directly. For example:
#Repository
public class OperationRepository {
// Yikes
private final EntityManager entityManager;
private QOperation operation = QOperation.operation;
#Autowired
public OperationRepositoryImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public Optional<Operation> findOneByIdAndType(Long operationId, OperationType type) {
JPAQuery<Operation> query = new JPAQuery<>(entityManager);
QOperation qOperation = QOperation.operation;
query.select(operation).from(operation)
.where(
operation.type.eq(type),
...
}
}
My understanding is that this is dangerous since EntityManager is not threadsafe and is being managed here as a field. I don't see an explicit definition in any of our configuration files to provide an EntityManager bean so am not sure what Spring does in this case.
I am going to start on the fix for using #PersistenceContext here instead but wanted to understand what the impact is on this being in production for so long and what consequences might have come from it.
Would we be limiting our connection pool size to the number of single entitymanagers in our repository beans? Are there any other dangers it could have caused? Or am I making too much of it?
It really depends on the configuration of your application context, which might get configured by Spring Boot if you are using that, but in general and with a typicals setup this is not a problem.
In such a setup the application context doesn't contain a single (or a limited set of) EntityManager instance but an EntityManagerFactory which can create EntityManager instances on demand.
And you don't get injected a normal EntityManager either, but a proxy which will point to different instances upon different calls, typically so that each thread has its own EntityManager and after a web request is completed the next request handled by the same thread gets a fresh instance.
If you are still concerned, I recommend to use a debugger to inspect the EntityManager and confirm that it is indeed a proxy and that it delegates to different actual instances for different threads.
You might also want to take a look at this question about Spring Scopes which is the underlying abstraction for this: Spring Bean Scopes
I got interested in how Spring's #Transactional works internally, but everywhere I read about it there's a concept of proxy. Proxies are supposed to be autowired in place of real bean and "decorate" base method with additional transaction handling methods.
The theory is quite clear to me and makes perfect sense so I tried to check how it works in action.
I created a Spring Boot application with a basic controller and service layers and marked one method with #Transactional annotation. Service looks like this:
public class TestService implements ITestService {
#PersistenceContext
EntityManager entityManager;
#Transactional
public void doSomething() {
System.out.println("Service...");
entityManager.persist(new TestEntity("XYZ"));
}}
Controller calls the service:
public class TestController {
#Autowired
ITestService testService;
#PostMapping("/doSomething")
public ResponseEntity addHero() {
testService.doSomething();
System.out.println(Proxy.isProxyClass(testService.getClass()));
System.out.println(testService);
return new ResponseEntity(HttpStatus.OK);
}}
The whole thing works, new entity is persisted to the DB but the whole point of my concern is the output:
Service...
false
com.example.demo.TestService#7fb48179
It seems that the service class was injected explicitly instead of proxy class. Not only "isProxy" returns false, but also the class output ("com.example.demo.TestService#7fb48179") suggests its not a proxy.
Could you please help me out with that? Why wasn't the proxy injected, and how does it even work without proxy? Is there any way I can "force" it to be proxied, and if so - why the proxy is not injected by default by Spring ?
There's not much to be added, this is a really simple app. Application properties are nothing fancy either :
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=superSecretPassword
spring.datasource.url=jdbc:mysql://localhost:3306/heroes?serverTimezone=UTC
spring.jpa.hibernate.ddl-auto=create-drop
Thank you in advance!
Your understanding is correct, but your test is flawed:
When the spring docs say "proxy", they are referring to the pattern, not a particular implementation. Spring supports various strategies for creating proxy objects. One of these is the java.lang.reflect.Proxy you tested for, but by default spring uses a more advanced technique that generates a new class definition at runtime that subclasses the actual implementation class of the service (and overrides all methods to apply transaction advice). You can see this in action by checking testService.getClass(), which will refer to that generated class, or by halting execution in a debugger, and inspecting the fields of targetService.
The reason that toString() refers to the original object is that the proxy implements toString() by delegating to its target object, which uses its class name to build the String.
Similar questions have been asked, but don't quite address what I'm trying to do. We have an older Seam 2.x-based application with a batch job framework that we are converting to CDI. The job framework uses the Seam Contexts object to initiate a conversation. The job framework also loads a job-specific data holder (basically a Map) that can then be accessed, via the Seam Contexts object, by any service down the chain, including from SLSBs. Some of these services can update the Map, so that job state can change and be detected from record to record.
It looks like in CDI, the job will #Inject a CDI Conversation object, and manually begin/end the conversation. We would also define a new ConversationScoped bean that holds the Map (MapBean). What's not clear to me are two things:
First, the job needs to also #Inject the MapBean so that it can be loaded with job-specific data before the Conversation.begin() method is called. Would the container know to pass this instance to services down the call chain?
Related to that, according to this question Is it possible to #Inject a #RequestScoped bean into a #Stateless EJB? it should be possible to inject a ConservationScoped bean into a SLSB, but it seems a bit magical. If the SLSB is used by a different process (job, UI call, etc), does it get separate instance for each call?
Edits for clarification and a simplified class structure:
MapBean would need to be a ConversationScoped object, containing data for a specific instance/run of a job.
#ConversationScoped
public class MapBean implements Serializable {
private Map<String, Object> data;
// accessors
public Object getData(String key) {
return data.get(key);
}
public void setData(String key, Object value) {
data.put(key, value);
}
}
The job would be ConversationScoped:
#ConversationScoped
public class BatchJob {
#Inject private MapBean mapBean;
#Inject private Conversation conversation;
#Inject private JobProcessingBean jobProcessingBean;
public void runJob() {
try {
conversation.begin();
mapBean.setData("key", "value"); // is this MapBean instance now bound to the conversation?
jobProcessingBean.doWork();
} catch (Exception e) {
// catch something
} finally {
conversation.end();
}
}
}
The job might call a SLSB, and the current conversation-scoped instance of MapBean needs to be available:
#Stateless
public class JobProcessingBean {
#Inject private MapBean mapBean;
public void doWork() {
// when this is called, is "mapBean" the current conversation instance?
Object value = mapBean.getData("key");
}
}
Our job and SLSB framework is quite complex, the SLSB can call numerous other services or locally instantiated business logic classes, and each of these would need access to the conversation-scoped MapBean.
First, the job needs to also #Inject the MapBean so that it can be loaded with job-specific data before the Conversation.begin() method is called. Would the container know to pass this instance to services down the call chain?
Yes, since MapBean is #ConversationScoped it is tied to the call chain for the duration starting from conversation.begin() until conversation.end(). You can think of #ConversationScoped (and #RequestScoped and #SessionScoped) as instances in ThreadLocal - while there exists an instance of them for every thread, each instance is tied to that single thread.
Related to that, according to this question Is it possible to #Inject a #RequestScoped bean into a #Stateless EJB? it should be possible to inject a #ConservationScoped bean into a SLSB, but it seems a bit magical. If the SLSB is used by a different process (job, UI call, etc), does it get separate instance for each call?
It's not as magical as you think if you see that this pattern is the same as the one I explained above. The SLSB indeed gets a separate instance, but not just any instance, the one which belongs to the scope from which the SLSB was called.
In addition to the link you posted, see also this answer.
Iv'e tested a similar code to what you posted and it works as expected - the MapBean is the same one injected throughout the call. Just be careful with 2 things:
BatchJob is also #ConversationScoped but does not implement Serializable, which will not allow the bean to passivate.
data is not initialized, so you will get an NPE in runJob().
Without any code samples, I'll have to do some guessing, so let's see if I got you right.
Would the container know to pass this instance to services down the call chain?
If you mean to use the same instance elsewhere in the call, then this can be easily achieved by making the MapBean an #ApplicationScoped bean (or, alternatively, and EJB #Singleton).
it should be possible to inject a ConservationScoped bean into a SLSB, but it seems a bit magical.
Here I suppose that the reason why it seems magical is that SLSB is in terms of CDI a #Dependent bean. And as you probably know, CDI always creates new instance for dependent bean injection point. E.g. yes, you get a different SLS/Dependent bean instance for each call.
Perhaps some other scope would fit you better here? Like #RequestScoped or #SessionScoped? Hard to tell without more details.
Say I have the following class...
#Controller
public class WebController {
#Autowired PersonService personService;
#RequestMapping(value = "/get", method = RequestMethod.GET)
#ResponseBody
#Scope("session")
public List<Player> getPerson(String personName) {
return playerService.getByName(personName);
}
}
Now this invokes the following service...
#Service("playerService")
public class PlayerServiceImpl implements PlayerService {
private List<Player> players;
#Override
#Transactional
public List<Player> getByName(final String name) {
if (players == null) {
players = getAll();
}
return getValidPlayers(name);
}
If I initially start my application, players is null, correctly, then when in the same session, I invoke this method again with a new value, players is no longer null, as you would expect. However, no new thread appears to be being created, if I open a new browser window (therefore creating a new session) and invoke this method, it still has the values from the previous session.
Why is #Scope("session") not creating a new thread in the thread pool?
I've specified <context:component-scan base-package="com." /> in my servlet-context as expected, everything works fine apart from the service methods are all acting as singletons rather than creating a new thread per session like say a Java EE container.
If players was marked as static I'd understand.
I've also tried marking my controller as #Scope("session") (as shown below) but this appears to have no impact either. What's the best way to make my Spring app create a new thread for a new session?
#Controller
#Scope("session")
public class PlayerController {
You are using #Scope annotation the wrong way.
Quoting the docs:
When used as a type-level annotation in conjunction with the Component annotation, indicates the name of a scope to use for instances of the annotated type.
When used as a method-level annotation in conjunction with the Bean annotation, indicates the name of a scope to use for the instance returned from the method.
So you can annotate either a spring component bean or a method that creates a bean if you're using java config. Java config is the only reason it even compiles (it wouldn't in pre 3.0 spring)
In your case that annotation is on a normal bean method where it doesn't mean anything.
Solving the right problem
It looks like you're trying to implement db cache by storing query results in a List<Player> players.
Don't do that. Use one of the prebuilt cache abstractions (spring has a very nice one) instead.
So where should #Scope go?
Annotating #Controller with #Scope("session") won't help as it will create session scoped controllers but the service they have injected is still a singleton.
Annotating only Service bean won't work either, cause #Controller is a singleton and it's dependencies are autowired on application startup.
Annotating both #Service and #Controller might work, but seems a bit heavy handed.
It's better to avoid state at all.
New threads are created for each request.
Your service has an instance variable (players) which is not threadsafe - it is shared by all threads. Any spring bean - including controllers and services are by default a singleton, you need to specify on the service annotation its scope.
#Service("playerService")
#Scope("session")
public class PlayerServiceImpl
But its best(simpler, easier to scale) to keep beans singletons and not rely on instance variables (unless they are also managed by spring/threadsafe/singletons).
We have some JavaEE5 stateless EJB bean that passes the injected EntityManager to its helpers.
Is this safe? It has worked well until now, but I found out some Oracle document that states its implementation of EntityManager is thread-safe. Now I wonder whether the reason we did not have issues until now, was only because the implementation we were using happened to be thread-safe (we use Oracle).
#Stateless
class SomeBean {
#PersistenceContext
private EntityManager em;
private SomeHelper helper;
#PostConstruct
public void init(){
helper = new SomeHelper(em);
}
#Override
public void business(){
helper.doSomethingWithEm();
}
}
Actually it makes sense.. If EntityManager is thread-unsafe, a container would have to do
inercept business()
this.em = newEntityManager();
business();
which will not propagate to its helper classes.
If so, what is the best practice in this kind of a situation? Passing EntityManagerFactory instead of EntityManager?
EDIT: This question is very interesting so if you are interested in this question, you probably want to check out this one, too:
EDIT: More info.
ejb3.0 spec
4.7.11 Non-reentrant Instances
The container must ensure that only one
thread can be executing an instance at
any time. If a client request arrives
for an instance while the instance is
executing another request, the
container may throw the
javax.ejb.ConcurrentAccessException to
the second client[24]. If the EJB 2.1
client view is used, the container may
throw the java.rmi.RemoteException to
the second request if the client is a
remote client, or the
javax.ejb.EJBException if the client
is a local client.[25] Note that a
session object is intended to support
only a single client. Therefore, it
would be an application error if two
clients attempted to invoke the same
session object. One implication of
this rule is that an application
cannot make loopback calls to a
session bean instance.
And,
4.3.2 Dependency Injection
A session bean may use dependency injection
mechanisms to acquire references to
resources or other objects in its
environment (see Chapter 16,
“Enterprise Bean Environment”). If a
session bean makes use of dependency
injection, the container injects these
references after the bean instance is
created, and before any business
methods are invoked on the bean
instance. If a dependency on the
SessionContext is declared, or if the
bean class implements the optional
SessionBean interface (see Section
4.3.5), the SessionContext is also injected at this time. If dependency
injection fails, the bean instance is
discarded. Under the EJB 3.0 API, the
bean class may acquire the
SessionContext interface through
dependency injection without having to
implement the SessionBean interface.
In this case, the Resource annotation
(or resource-env-ref deployment
descriptor element) is used to denote
the bean’s dependency on the
SessionContext. See Chapter 16,
“Enterprise Bean Environment”.
I used a similar pattern, but the helper was created in #PostConstruct and the injected entity manager was passed in the constructor as parameter. Each EJB instance had its own helper and thread-safety was guaranteed then.
I also had a variant were the entity manager was not injected (because the EJB wasn't using it altogether), so the helper has to look it up with InitialContext. In this case, the Persistence context must still be "imported" in the parent EJB with #PersistenceContext:
#Stateless
#PersistenceContext(name="OrderEM")
public class MySessionBean implements MyInterface {
#Resource SessionContext ctx;
public void doSomething() {
EntityManager em = (EntityManager)ctx.lookup("OrderEM");
...
}
}
But it's actually easier to inject it (even if the EJB doesn't use it) than to look it up, especially for testability.
But to come back to your main question, I think that the entity manager that is injected or looked up is a wrapper that forwards to the underlying active entity manager that is bound to the transaction.
Hope it helps.
EDIT
The section § 3.3 and § 5.6 in the spec cover a bit the topic.
I've been using helper methods and passed the EntityManager there, and it is perfectly OK.
So I'd recommend either passing it to methods whenever needed, or make the helper a bean itself, inject it (using #EJB) and inject the EntityManager there as well.
Well, personally, I wouldn't like to have to pass the Entity Manager to all my POJOs in my constructors or methods. Especially for non-trivial programs where the number of POJOs is large.
I would try to create POJOs/HelperClasses that deal with the Entities returned by the EntityManager, instead of using the entitymanager directly.
If not possible, I guess I'd create a New EJB Bean.