Please see the example below. I wonder if there will be any difference if I specify the scope or not below. Thanks
#RestController
#RequestScope
#RequestMapping("/api/v1/user")
public class UserResource {
#GetMapping("/addresscheck")
public String getAddress() {
return customer.getAddress();
}
}
// Here does it matter I define the scope or not? is it still going to be treated as one per request?
#RestController
#RequestMapping("/api/v1/user")
public class UserResource {
#GetMapping("/addresscheck")
public String getAddress() {
return customer.getAddress();
}
}
By default, all Spring managed beans have singleton scope. So in your second implementation, only one UserResource object will be created by Spring and that will be provided every time a request for the specified URL is to be fulfilled.
However, in the first implementation, since you are annotating UserResource with #RequestScope, Spring will create a new controller object to serve each request. This means that any state information you may be maintaining in UserResource will be lost. All member variables of UserResource will also be created anew for each request.
Although I am curious as to why you would want a controller to be request scoped? Could you please share your use-case, if possible?
Here is a good article to read on the subject: Spring Bean Scopes
Related
I'm using a Java8/Spring Boot 2 application. I want to inject a request-scoped bean into a singleton bean. The official documentation highlights that either a proxy or ObjectFactory/Provider should be used to ensure always getting the correctly scoped bean at runtime in the singleton bean. However, the #RequestScope annotation seems to "automatically" set some kind of proxy, as explained in the answer to this question.
I'm now wondering if the following three implementations are in fact identical and which one is preferred?
Approach 1: explicitly using objectFactory<>
#Component
#RequestScope
public class MyRequestScopedBean{...}
#Component
public class MySingletonBean{
#Autowired
private ObjectFactory<MyRequestScopedBean> myRequestScopedBean
}
Approach 2: inject normally, assuming the request scoped bean is proxied automatically?
#Component
#RequestScope
public class MyRequestScopedBean{...}
#Component
public class MySingletonBean{
#Autowired
private MyRequestScopedBean myRequestScopedBean
}
Approach 3: using #Configuration and #Bean because I don't know the difference and I'm worried they behave differently.
#Comfiguration
public class myBeanConfig{
#Bean
#RequestScope
public MyRequestScopedBean getRequestScopedBean(){return new MyRequestScopedBean();}
}
#Component
public class MySingletonBean{
#Autowired
private MyRequestScopedBean myRequestScopedBean
}
I would prefer approach 2, because it is concise and handles the scoping/proxying automatically.
Would the answer change if my #Autowired bean is declared as a final field? I'm worried making it final somehow prevents the proxy from fetching the correctly fetching the new bean every request.
I have been using the 2nd approach in my projects and I have zero issues so far. The documentation does not mention it's a MUST to use ObjectFactory too. Don't think too much. If you run into any problems, you will see the error very clearly in the console. There's no reason to be afraid until you have an actual issue to deal with.
Yes, with #RequestScope the proxy is already default activated, the effect exactly equal to #Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyModel = ScopedProxyMode.TARGET_CLASS)
I have searched the forum form my query but could not find a answer.
I am new to spring mvc so i am little bit confused it will be great if some one helps me out,
I have a spring mvc application, i get some data from request parameter, i have to maintain that data through out the session. how could i achieve this using Spring 3.0.3.
I had some idea in mind to implement this
1> create a pojo with session scope
2> Then in controller autowire the pojo and populate the pojo.
3> Since it is in session scope the value populated should be available throughout the session
Please let me know if i am on the right track.
Thanks.
The idea you said is one way to work with session scoped beans. You can define your session scoped POJO:
#Component
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class YourSessionBean{
...
}
and then you can inject it in your Controller classes:
#Controller
public class YourController {
#Autowired
private YourSessionBean yourSessionBean;
...
}
You can also use #SessionAttributes to store your POJO into session:
public class YourObject {
...
}
and you can use #SessionAttributes annotation in your controller to put an instance of YourObject into session:
#Controller
#SessionAttributes("yourObj")
public class YourController {
...
#RequestMapping(value="/url")
public ModelAndView process(...) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("yourObj", new YourObject()); // this will put YourObj into session
return modelAndView;
}
}
But, while using #SessionAttributes, you should consider below block of statements (copied from #SessionAttributes Doc):
NOTE: Session attributes as indicated using this annotation correspond
to a specific handler's model attributes, getting transparently stored
in a conversational session. Those attributes will be removed once the
handler indicates completion of its conversational session. Therefore,
use this facility for such conversational attributes which are
supposed to be stored in the session temporarily during the course of
a specific handler's conversation.
For permanent session attributes, e.g. a user authentication object,
use the traditional session.setAttribute method instead.
You can also use HttpSession as a method argument for your #RequestMapping handler methods and then add your POJO class to the session:
#Controller
public class YourController {
...
#RequestMapping(value="/url")
public ModelAndView process(HttpSession session,...) {
ModelAndView modelAndView = new ModelAndView();
session.setAttribute("yourObj", yourObj);
...
return modelAndView;
}
}
What does the scope annotation in Java guice mean?
Could someone give an example to explain how it works?
I see examples like this:
#Singleton
class Log {
void log(String message) { ... }
}
But singleton has nothing to do with scope, right?
Thanks!!!
Scopes allow you to reuse instances: for the lifetime of an application (#Singleton), a session (#SessionScoped), or a request (#RequestScoped).
http://code.google.com/p/google-guice/wiki/Scopes
It means that if your class is annotated with Singleton there will be only one object instantiated from this class which will be injected every time you will use this kind of bind.
When you use #RequestScoped you get every time new object per request
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).
I have some serious doubts regarding scope bean dependencies because of lack of spring knowledge.
I have read reference manual at 3.5.4.5 Scoped beans as dependencies and have implemented sucessfully an example about it.
However before going further more, I wanted to share my concerns.
Let me to share my use case and little implementation details
For each user request I would like to create a city for per user.
#Configuration
public class CityFactory{
#Bean(name = {"currentCity" , "loggedInCity"})
#Scope(value = WebApplicationContext.SCOPE_REQUEST,proxyMode = ScopedProxyMode.TARGET_CLASS)
#Autowired
public CityBean getCityBean(HttpServletRequest request) {
return CityUtil.findCityWithHostName(request.getServerName());
}
For each request I want to inject this city into a singleton scoped controller which is default scope for controller.
#RequestMapping("/demo")
#Controller
public class DemoController {
#Autowired
CityBean city;
#RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
public ModelAndView helloWorld(#PathVariable("name") String name, Model model) {
Map<String, Object> myModel = new HashMap<String, Object>();
model.addAttribute("hello", name);
model.addAttribute("test", "test in " + city.getDomainName() + " !!! ");
return new ModelAndView("v3/test", "m", model);
}
}
My questions:
1) Is there any race condition? I am afraid of context switches which will destroy my application in a multi request environment.
2) I am aware of another solution which creating a controller per request but it is more error prone than current solution. Because another developer can forget scoping controllers to make request.
How can I make controllers globally request scope? Just because of being little curious.
Thanks...
No race conditions - each request has its own thread
But I think there's an easier way to do what you want. You can have your CityBean:
#Service
public class CityBean {
public String getDomainName(String serverName) {
// obtain the name based on the server name
}
}
And in your controller:
#Autowired CityBean bean
pass HttpServletRequest as argument to the method, and call cityBean.getDomainName(request.getServerName());
(If you use some ORM, perhaps you'll have a City entity, which you can fetch and pass around, just beware of lazy collections)
There are no race conditions here.
That's the point of scoped proxies - the instance of CityBean injected into DemoController is a proxy which delegates calls of its method to the actual request-bound instance of CityBean, so that each request works with its own CityBean.
I agree that you shouldn't make the controller itself request-scoped - it would be confusing for other people since it's not a typical approach in Spring MVC applications.
You can also follow the approach suggest by Bozho and get rid of request-scoped bean at all, though that approach has a drawback since it requires you to add extra argument to your controller methods.