How does Spring MVC handle multiple users - spring

I am using spring from more than 6 months. I am not able to understand this underlying mechanism related to the below scenario.
I have a spring web app. Now I autowired the model in controller. Based on url matching it calls respective method. all my methods are singleton.
Now when two users are opening app at same time spring is able to run them parallelly and give results to them. I didnt understand how can it do this. i mean as the bean is singleton it has to either the wait till the bean is not used or overwrite the data in the bean. But spring is working correctly. Can someone explain this behaviour with some analogy.
To explain my question clearly below is a piece of code:
My default controller is simple one:
#Autowired
private AppModel aModel;
public AppModel getModel(){
return aModel;
}
public void setModel(AppModel aModel){
this.aModel = aModel;
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView defaultGetter(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView(getViewName());
mav.addObject("model", aModel);
Runtime.getRuntime().gc();
return mav;
}
Also can some one tell me when two clients open the app will two seperate models get generated when i use #autowired . If only one model bean exists for all clients then say the request from client 1 came in and it take me 30 sec to get results back. Now if second client sends request in 3rd sec then will the first clients request gets overwritten?
I think I am getting confused. Can some one clarify how this magic is happening?
Thanks

Every web request generate a new thread as explained in this thread.
Spring manages different scopes (prototype, request, session, singleton). If two simultaneous requests access a singleton bean, then the bean must be stateless (or at least synchronized to avoid problems). If you access a bean in scope request, then a new instance will be generated per request. Spring manages this for you but you have to be careful and use the correct scope for your beans. Typically, your controller is a singleton but the AppModel has to be of scope request, otherwise you will have problems with two simultaneous requests. This thread could also help you.
About your last question "how this magic is happening?", the answer is "aspect/proxy". Spring create proxy classes. You can imagine that Spring will create a proxy to your AppModel class. As soon as you try to access it in the controller, Spring forwards the method call to the right instance.

Related

Does an autowired FluentProducerTemplate need to have its headers and body cleared before use within same service?

Autowired FluentProducerTemplate in a service bean will intermittently have a header set from a previous call in another method in the same service bean. I set the CamelOlingo4.keyPredicate is the header in this case.
FluentProducerTemplate producerTemplate;
UserAccount account = producerTemplate
.withHeader("CamelOlingo4.$select", "cva_useraccountid,statuscode,emailaddress,cva_firstname,cva_lastname,cva_password,cva_lastlogout,cva_lastlogin,cva_lastloginattempt,cva_lockeduntil,cva_loginattemptcount,_cva_contact_value")
.withHeader("email",username)
.withHeader("activeStatus",MSDynamicsAccountStatusCodes.ACTIVE.toString())
.withHeader("lockedStatus",MSDynamicsAccountStatusCodes.LOCKED.toString())
.to("direct:login")
.request(UserAccount.class);
And my route definition:
from("direct:login")
.id("routes.id.login")
.toD("olingo4://read/{{route.login}}?$filter=emailaddress eq '${header.email}' and (statuscode eq ${header.activeStatus} or statuscode eq ${header.lockedStatus})").log("Response from Olingo: ${body}")
.process(new OlingoProcessor());
I do fire an async request route with the keyPredicate upon successful login...
producerTemplate
.withHeader("CamelOlingo4.keyPredicate", userId)
.withHeader("Content-Type", "application/json")
.withBody(user)
.to("direct:tracklogin")
.asyncSend();
And route defined for track:login:
from("direct:tracklogin")
.id("routes.id.track.login")
.marshal()
.json(JsonLibrary.Jackson)
.convertBodyTo(String.class)
.log("JSON Body: ${id} ${body}")
.to("olingo4://patch/{{route.patch.track-login}}");
Random times, the "direct:login" route will have the keyPredicate set in the header, causing an error in my OlingoProcessor, since I'mn not getting the expected object back from the exchange body. (Olingo Object is different when querying with a keyPredicate)
Not sure if the issue lies with my implementation, the camel-olingo4 comp or the FluentProducerTemplate itself... But I do see there is a clearAll() method on the FluentProducerTemplate. I'm suspecting i need to call it whenever i use the autowired producer template within the same service bean. Just need some confirmation...
As Spring default scope is singleton, indeed the injected producer template bean instance will be reused, and the clearAll() should be called before setting headers, body, etc...
Of course, another possible solution would be to create each time a brand new producer template instance:
FluentProducerTemplate producerTemplate = context.createFluentProducerTemplate();
UserAccount account = producerTemplate.withHeader(...)
TL;DR
Does an autowired FluentProducerTemplate need to have its headers and body cleared before use within same service?
In Camel 2, yes. In Camel 3, no.
Long Story
The CamelAutoConfiguration from Camel's Spring Boot Starter create a FluentProducerTemplate with no specific scope, hence Spring's default scope singleton is applied and you have only one instance per application.
The FluentProducerTemplate is thread-safe. In Camel 2, thread-safety is achieved by storing the message body and headers in ThreadLocals. If you don't clear the headers after/before usage you may occasionally see left-overs from previous invocations. So, yes, you'd have to call clearHeader() or clearAll() manually.
The situation in Camel 3 is a bit more relaxed. There, thread-safety is achieved by producing new instances of FluentProducerTemplate whenever you call a method that would otherwise modify the template (headers, body). Clearing the values is not strictly necessary anymore as far as I can tell.

Why Spring Boot inject same HttpServletResponse object to my Controller method for different request?

I wonder why spring boot inject same response object to my controller method parameter for different request, i use it like follow:
#Controller
#Slf4j
#Profile("default")
#RequestMapping("/test")
public class TestController {
#RequestMapping("/test")
#ResponseBody
public void getDeviceImage(#RequestParam("serialNumber") String serialNumber, HttpServletResponse response) {
return balabala;
}
}
I add a breakpoint before return command, and i find that response object's address is same for different request.
I want to write some thing to response.getOutputStream(), and i found there exists previous buffered data.
HttpServletResponse can be used if you need to add some extra meta information like cookies etc. By default even if you don't specify HttpServletResponse in the arguments, in typical MVC, model is added to the newly constructed response before propagating to the view.
If you just need to return some response back, say a model or entity or a simple JSON, you don't have to manually mess the HttpServletResponse. Unless you want to dig through cookies or headers etc.,. In your code, if you don't need to care about this, you might probably not need it.
As per the API doc for HttpServletResponse:
The servlet container creates an HttpServletResponse object and passes
it as an argument to the servlet's service methods (doGet, doPost,
etc).
What you see is probably the default configurations that Spring sets up.
With #ResponseBody, the return type is directly written back to response.
https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
Finally, i find Response will been reused all the time, and Response's recycle method will been invoked for each request(org.apache.catalina.connector.Response#recycle).
But by default facade&outputStream&writer will not been cleaned, so i make system property "org.apache.catalina.connector.RECYCLE_FACADES" to be "true", after that issue disappears.

Spring: new() operator and autowired together

If I use Spring, which of these two methods is more correct.
Can I use the new() operator even if I use dipendency injection?.Can I mix both?
I would like to have some clarification on these concepts.
Thanks
First method:
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(new User());
return "index";
}
Second Method:
#Autowired
User user;
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(user);
return "index";
}
By using dependency injection does not mean that the use of new operator is automatically prohibited throughout your code. It's just different approaches applied to different requirements.
A web application in spring is composed of a number of collaborating beans that are instantiated by the framework and (unless overriding the default scope) are singletons. This means that they must not preserve any state since they are shared across all requests (threads). In other words if you autowire the User object (or any other model attribute), it is created on application context initialization and the same instance is given to any user request. This also means that if a request modifies the object, other requests will see the modification as well. Needless to say this is erroneous behavior in multithreaded applications because your User object (or other model attribute) belongs to the request, so it must have the very narrow scope of a method invocation, or session at most.
You can also have spring create beans with different scopes for you, but for a simple scenario of a model attribute initialization, the new operator is sufficient. See the following documentation if interested in bean scopes : Bean scopes
So in your use case, the second method is totally wrong.
But you can also delegate the creation of your model attributes to spring if they are used as command objects (i.e. if you want to bind request parameters to them). Just add it in the method signature (with or without the modelattribute annotation).
So you may also write the above code as
#RequestMapping(method=RequestMethod.GET)
public String create(#ModelAttribute User user){
return "index";
}
see also : Supported method argument types
If you want your beans to be "managed" by Spring (for e.g. to use with Dependency Injection or PropertySources or any other Spring-related functionality), then you do NOT create new objects on your own. You declare them (via XML or JavaConfig) and let Spring create and manage them.
If the beans don't need to be "managed" by Spring, you can create a new instance using new operator.
In your case, is this particular object - User - used anywhere else in code? Is it being injected into any other Spring bean? Or is any other Spring bean being injected in User? How about any other Spring-based functionality?
If the answer to all these questions is "No", then you can use the first method (create a new object and return it). As soon as the create() method execution is complete, the User object created there would go out of scope and will be marked for GC. The User object created in this method will eventually be GC-ed.
Things can be injected in two ways in a Spring MVC applications. And yes, you can you can mix injection and creation if doing right.
Components like the controller in your example are singletons managed by the application context. If you inject anything to them it is global, not per request or session! So a user is not the right thing to inject, a user directory can be. Be aware of this as you are writing a multithreaded application!
Request related things can be injected to the method like the used locale, the request, the user principal may be injected as parameters, see a full list at Spring MVC Documentation.
But if you create a model attribute you may use new() to create it from scratch. I will not be filled by spring but to be used by your view to display data created by the controller. When created in the request mapped method that is ok.

Do Spring transactions propagate through new instantiations

I'm working on a bunch of legacy code written by people before me and I'm confused about a particular kind of setup and wonder if this has ever worked to begin with.
There is a managed bean in spring that has a transactional method.
#Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
public boolean updateDraftAndLivePublicationUsingFastDocumentsOfMySite(List<FastDocumentLite> fastDocumentLites, Long mySiteId) throws Exception { ... }
Now inside that method I find new instantiations calling update methods fe:
boolean firstFeed = new MySiteIdUpdate(publishing, siteDao, siteDomainService).update(siteId, fastDocumentLites.get(0).getMySiteId());
From my understanding on IOC this new class isn't managed by spring , it's just a variable in the bean. Now going further inside the update method you see another service gets called.
#Transactional(propagation=Propagation.REQUIRED, rollbackFor=Throwable.class)
public void activateSubdomainForSite(Long siteId, boolean activationOfSite)
So if there is a transaction open it should be propagated into this service. But here is what I don't get if that MySiteIdUpdate object isn't managed by spring does the first transaction move forward to the activateSubdomainForSite method ?? Or is another transaction being opened here. I looked in the logs and I believe it to be the latter but I rather ask the experts for a second oppinion before I proclame this legacy code to be complete rubbish to the project lead. I'm suffering with a StaleStateException somewhere further down the road and I'm hoping this has anything to do with it.
I think the code is correct, and the second #Transactional should reuse the existing transaction.
Because:
1) Spring Transaction handling is done either by Proxies or by AspectJ advices. If it is done by Proxies then it is required that MySiteIdUpdate invoke an instance that is injected (this is what you did). If you use AspectJ, then it should work anyway.
2) The association Transactions to the code that use is done by the Thread, this mean, as long as you "are" in the thread which started the transaction you can use it. (you do not start an new thread, so it should work)
An other way to explain: It is perfect legal when you have some method in your call hierarchy that does not belong to an spring bean. This should not make the transaction handling fail.

Initialize Singletons in Spring Framework 3 MVC

I am writing Spring 3.1.0 MVC based application. The problem is: i want to put some objects in a singleton object (current HttpServletRequest and HttpSevletResponse) to use them in other objects(Spring Controllers). But couldn't do so. I tried to extend DispatcherServlet, overriding both doService and doDispatch. Also tried to implement own HandlerInterceptor. No result.
Where can I initialize my singleton objects? And where is Spring Frameworks's entry point and destroy point (i.e. like init() and destroy() methods or lifecycle)?
The current HttpServletRequest and HttpServletResponse are available as method arguments to your controller methods:
#RequestMapping("/foo")
public String foo(HttpServletRequest request) {
}
I believe you can also #Inject them in your controller. A proxy will be injected, and each time you refer to them the current ones will be used. (I'm not 100% certain about this one)
A third option is to use the RequestContextHolder container, and get everything from there.

Resources