In a struts 2 and spring web based application, please consider below sample.
The BookManager has an action which returns a Map of books to client. It get the map from service layer which is injected by Spring
public class BookManager extends ActionSupport {
//with setter and getter
private Map<String, BookVO> books;
#inject
BookService bookservice
#Action("book-form")
public String form(){
setBooks(bookservice.getAllBooks());
}
}
The service layer gets the book list from DB an returns a MAP.
#Named
public class BookService(){
private Map<String,BookVO> books;
public Map<String,BookVO> getAllBooks(){
books = new HashMap<String,BookVO>();
//fill books from DB
return books;
}
}
I have tested and found that the above implementation is not thread safe.
I can make the code thread safe by removing private field books from BookService and use it like method HashMap<String,BookVO>() books = new HashMap<String,BookVO>();. Why this change make the code thread safe ?
The struts action is thread safe, shouldn't this assure that the even non thread safe spring service runs in a thread safe manner.
If I use the non thread safe version of service in my action, by making a new service object instead of using spring inject, I will face no issue. Why? If the service is not thread safe why making a new instance and calling it will be thread safe!
I can make the code thread safe by removing private field books from BookService and use it like method HashMap() books = new HashMap();. Why this change make the code thread safe ?
Because method-level variables are thread safe, while class-level variables are not.
The struts action is thread safe, shouldn't this assure that the even non thread safe spring service runs in a thread safe manner ?
Nope. It depends.
If I use the non thread safe version of service in my action, by making a new service object instead of using spring inject, I will face no issue. Why? If the service is not thread safe why making a new instance and calling it will be thread safe!
If you instantiate it manually in the action, you are creating an instance of that object private to that action, thread-safe since the actions are ThreadLocal, and managed by you (that's means if your BookService class has some #Inject in it, the container won't resolve them).
If instead you have the DI managed by the container, the instance is not thread-safe; what you're using (#Inject, #Named) is more than "Spring", it's Java EE, is an implementaton of the JSR-330 (Dependency Injection) available only in CDI-enabled applications (JSR-299).
CDI beans are not thread safe. You should use EJB3's #Singleton for this to be thread-safe, but you really don't need to retain that attribute at class-level, since it's used only to be returned, then left there to be overwritten the next time.
BTW consider using reference CDI (Weld in JBOSS) with the Struts2 CDI-plugin, it's worthy of a try.
Related
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.
How should I create a controller which is thread safe?
As per the best practice controllers are singleton.
Consider the below code in which im storing user data through a autowired service Object ,which makes my code stateful.
How would i make the below code thread safe.
#RestController
class ApiController {
#Autowired
IDbService< User > iDBService;
#RequestMapping(value = "/api/adduser", method = RequestMethod.POST)
public ResponseEntity<User> createUser(#RequestBody User user){
User savedUser=iDBService.create(user);
return new ResponseEntity<User>(savedUser, HttpStatus.CREATED);
}
Here is my Service implementation.
I have shared variable in my service
public class IDbServiceImpl<T> implements IDBService<T>{
#Autowired
GenericRepository<T, Serializable> genericRepository;
#Override
public T create(T object) {
return genericRepository.save(object);
}
}
Your controller is a singleton by default and your service is singleton by default too.
Therefore in order to make them thread safe you have to make sure that the operations that take place inside the service must be thread safe, in case of changing the state of an object inside the service ie. a list.
In case of using a rdbms then you have a transaction related problem.
If you use spring and Jpa, the transaction manager will take care for your updates provided that you use #Transactional. In case of plain jdbc method then you can either use pure jdbc and do the transaction handling on your own or use spring-jdbc that comes with a transaction manager.
If you want the database rows not to be changed in case of a write in progress then you have to take into consideration row-locking related mechanisms. – gkatzioura Feb 7 at 15:23
In case of JPA using #Transactional will do the work. However depending on your application you might have to consider locking. Check this article on locking with jpa.
Controllers are singletons, therefore they should be implemented in a thread safe manner.
Design your application in a way that controllers are stateless. Add transactional support in your #Repository layer.
Example:
public class GenericRepository<T, Serializable> {
#Transactional
public void save(T object) {
// save user
}
}
You could use Spring declarative transaction management mechanism. The #Transactional annotation itself defines the scope of a single database transaction.
Your controller looks thread safe. As there is no instance variable storing the state. User object will be different for each request and will be resolved by the MVC framework.
I was wondering if next scenario is thread-safe:
I have a spring controller with method
#Autowired
private JobService jobService;
public String launch(#ModelAttribute("profile") Profile profile){
JobParameters jobParams = MyUtils.transform(profile);
jobService.launch(profile.getJobName(), jobParams);
return "job";
}
and I have MyUtils class with static method that transforms one kind of object to another... like so :
public class MyUtils {
public static JobParameters transform(Profile profile) {
JobParametersBuilder jpb = new JobParametersBuilder();
jpb.addString("profile.name", profile.getProfileName());
jpb.addString("profile.number", String.valueOf(profile.getNumber()));
return jpb.toJobParameters();
}
}
Classes JobParametersBuilder , JobParameters and JobService are from spring batch core project. Profile class is simple POJO.
The question really is... is this static method transform thread-safe since it is dealing with object instances, although all of those instances are locally created for the method.
This concrete code IS thread safe if some conditions are met. Here is explanation:
launch method is called from Spring boot controller. Every call that comes to Spring boot controller is called from different thread and that thread is taking execution to the end of the call stack(unless you call some asynchronous call inside that thread). Tomcat can handle 200 threads in same time by default. Which means you can have 200 calls to your Controllers in same time and they will all be in separate threads. Which means launch is thread safe.
Profile is passed to the transform method and if it is simple POJO it is thread safe, because on every call it will be new instance of Profile.
Inside transform method you are instantiate JobParametersBuilder every time which is thread safe if code inside toJobParameters is thread safe and doesn't keep any state of the JobParametersBuilder class or some other.
Singleton pattern allows to contain one instance per application thread.
How can I make sure only single instance of guava Service Manager is running per JVM ? So when ever it launches a new seperate entry java thread can check whether the service manager is running.
Why do you think that simply not creating multiple instances wouldn't work? Implement a ServiceManagerProvider as a singleton and use only serviceManagerProvider.get() for accessing the Service Manager.
Consider using Dependency Injection instead of the singleton (anti-)pattern:
#Singleton
public class ServiceManagerProvider implements Provider<ServiceManager> {
private final ServiceManager serviceManager = ...
#Overrride
public ServiceManager get() {
return serviceManager;
}
}
Here, you get a single instance per injector, which is exactly what you (should) want.
In servlet, because it's singleton except implement SingleThreadModel. Reference this article https://www.fortify.com/vulncat/en/vulncat/java/singleton_member_field_race_condition.html
But in EJB 3, I cannot find a similar document. And because container will create a pool to handle EJBs. I think the class variable should be safe, is it correct?
For example, classVar1 is a class variable, I initial it in constructor and use it later. In servlet, it may have problem, but in EJB 3, it should be ok, right?
#Stateles
public class HelloBean implements Hello {
ObjectXXX classVar1;
public HelloBean() {
ObjectXXX classVar1 = new ObjectXXX();
}
public String doHello(String message) {
return message + classVar1.method1();
}
}
And another question is that the resource (i.e. EntityManager in JPA) injected to EJB, it should be thread safe?
The container must let only 1 thread in particular EJB instance, so: each method can be executed by only a single thread and your variable is 'safe' (as you initialize it in the constructor or #PostConstruct method).
However, the SLSB (stateless EJB) should not be used to keep a state. The EJB is pooled, so you don't have any guarantee that you will return to the same instance. The SFSB is made for this purpose.
The EntityManager, as every instance field in the EJB, is thread safe.
However, the EntityManager itself is not thread safe and cannot be used in environment where more than 1 thread can access it (i.e. in Servlet). EntityManagerFactory should be used instead in such cases.