I really like to use spring stereotype annotated beans in spring MVC apps and would like to use Spring scope annotations to the full extend. No more need to fiddle around in HttpServletRequest or it' s session.
One thing isn' t really clear to me though and maybe someone could provide me with some insight or explanation on how to handle this. I have a cache implemented a singleton spring bean. It caches several object of a certain type "Foo". Foo is defined as a session scoped bean through annotations. The intended behavior is that each new session has it' s own "Foo" instance. How do I move the state of one of the cahced "foo" instances to the session scoped Foo (copy, clone or simple assignment)? I would like to achieve the same behavior of storing a Foo instance from the cache into the session available in a HttpSession, but this through the Spring session scoped objects. Goal is to remove all boilerplate code of moving to a HttpSession and retrieving from a HttpSession.
Example of how I define Foo:
#Component
#Scope(value="session",proxyMode=ScopedProxyMode.TARGET_CLASS)
public class Foo extends BaseEntity {
//Some stuff done here
private Long id;
}
Ok, so I solved this by declaring a session bean in which I stored the element selected from the cache... . This was actually easy solved.
Related
I have a service class that is being proxied by Spring, like so:
#Service
#Transactional
open class MyService { ... }
If I remove the open modifier, Spring complains that it needs to proxy the class to apply the #Transactional annotation tweaks.
However, this is causing issues when calling a function on the proxied service, which attempts to access a variable:
#Service
#Transactional
open class MyService {
protected val internalVariable = ...
fun doWork() {
internalVariable.execute() // NullPointerException
}
}
The internalVariable is assigned as part of its declaration, does not have any annotations (like #Autowired, etc.), and works fine when I remove the #Transactional annotation and the requirement for Spring to proxy the class.
Why is this variable null when Spring is proxying/subclassing my service class?
I hit a similar issue and the above comments by Rafal G & Craig Otis helped me-- so I'd like to propose that the following write up be accepted as an answer (or the comments above be changed to an answer and they be accepted).
The solution: open the method/field.
(I hit a similar case where it was a closed method that caused the problem. But whether it is a field/method the solution is the same, and I think the general cause is the same...)
Explanation:
Why this is the solution is more complicated and definitely has to do with Spring AOP, final fields/methods, CGLIB proxies, and how Spring+CGLIB attempts to deal with final methods (or fields).
Spring uses proxies to represent certain objects to handle certain concerns dealt with by Aspect Oriented Programming. This happens with services & controllers (especially when #Transactional or other advice is given that requires AOP solutions).
So a Proxy/Wrapper is needed with these beans, and Spring has 2 choices-- but only CGLIB is available when the parent class is not an interface.
When using CGLIB to proxy classes Spring will create a subclass called
something like myService$EnhancerByCGLIB. This enhanced class will
override some if not all of your business methods to apply
cross-cutting concerns around your actual code.
Here comes the real surprise. This extra subclass does not call super
methods of the base class. Instead it creates second instance of
myService and delegates to it. This means you have two objects now:
your real object and CGLIB enhanced object pointing to (wrapping) it.
From: spring singleton bean fields are not populated
Referenced By: Spring AOP CGLIB proxy's field is null
In Kotlin, classes & methods are final unless explicitly opened.
The magic of how Spring/CGLib when & how chooses to wrap a Bean in an EnhancerByCGLIB with a target delegate (so that it can use finalized methods/fields) I don't know. For my case, however the debugger showed me the 2 different structures. When the parent methods are open, it does not create a delegate (using subclassing instead) and works without NPE. However, when a particular methods is closed then for that closed method Spring/CGLIB uses a wrapped object with delegation to a properly initialized target delegate. For some reason, the actual invocation of the method is done with the context being the wrapper with its uninitialized field values (NULLs), causing NPE. (Had the method on the actual target/delegate been called, there should not have been a problem).
Craig was able to solve the problem by opening the property (not the method)-- which I suspect had a similar effect of allowing Spring/CGLib to either not use a delegate, or to somehow use the delegate correctly.
I went through some blogs and spring docs about the Spring singleton scope along with almost all spring singleton and DAO related question in stackoverflow.
I still do not have clear understanding of how the same object is injected to all the class which depend on it. I have learnt that the DAO needs to be stateless.
If the following DAO (sample dao having instance variable mainly to clear confusion) class is defined with default singleton scope and the same object is injected everytime, then there might be scenarios where department is null and therefore it won't set anything for department value instead use whatever the previous object value was.
public class UserDAO{
int userId;
Spring userDepartment;
// getter setter methods for userId and userDepartment
public boolean addUserToUserDetailsTable(int uId,
String name, String address, String department){
// set userId
userId = uId;
if(department!=null)
userDepartment = department;
// write code to add user to user table
// TO DO
// save user department data
addUserToUserDepartmentTable(userId, userDepartment);
}
public void addUserToUserDepartmentTable(int uId,
String department){
/* Code to save department data */
}
}
So if instead of using DI, if I manually call the DAO using new operator this problem won't be there.
new UserDAO().addUserToUserDetailsTable(id, "abc", null);
the above confusion generates following questions
how is spring creating and injecting singelton beans, is it really one and only one object which gets injected to all calling classes. If this is true then how the previous object values from above DAO class is reset.
won't the instance variable hold their values here userId, userDepartment if the same object is called from multiple class ?? Does stateless means the class cannot have instance variable.
does spring internally uses new object() to inject the beans.
or it creates an object of DAO class and makes multiple clones of the object, which i think is not possible because the DAO class is not implementing clonnable.
Please help me clearing the above confusion.
how is spring creating and injecting singelton beans, is it really one and only one object which gets injected to all calling classes.
Yes, it's injecting a single instance, always the same, of the DAO class. That's the definition of singleton: a single instance is created.
If this is true then how the previous object values from above DAO class is reset.
It's not reset.
won't the instance variable hold their values here userId, userDepartment if the same object is called from multiple class ??
Yes, the unique instance will hold the userId and department, since these are fields of the instance. You might run into problems trying to read and write these values, though, since they constitute shared mutable state, which is accessed concurrently from multiple threads without any synchronization.
Does stateless means the class cannot have instance variable.
In the strict sense, yes. But a DAO doesn't need to be stateless. It needs to be thread-safe, since the same instance is accessed from multiple threads concurrently. The best way to achieve that is to avoid having any state (so no instance variable). But this is hard to achieve for a DAO, which normally needs to have access to an injected DataSource, of JdbcTemplate, or EntityManager, or whatever. Since, however, these instance variables are normally injected by Spring during startup, before the DAO starts being used by multiple threads, and never written to during the lifetime of the application, that is thread-safe. Your code, however, has state, and the state is modified during the lifetime of the application, which makes it not safe.
does spring internally uses new object() to inject the beans.
It depends how the DAO bean is declared. It can be declared using JavaConfig, using a #Bean method calling the constructor. Most of the time, reflection is used to call the constructor. So there is no new MyDAO() in the code anywhere, but the constructor is still called (only once since it's a singleton), because that's the only way to create an instance of an object from scratch.
or it creates an object of DAO class and makes multiple clones of the object, which i think is not possible because the DAO class is not implementing clonnable.
That wouldn't be a singleton if it did that.
Singleton scope beans in Spring means one instance per container and the bean has to be stateless or else you will run into issues in cases of multi-threaded scenarios.
how is spring creating and injecting singelton beans, is it really
one and only one object which gets injected to all calling classes.
Spring creates once instance at startup and passes the same reference to all the calling objects which has requested for the same via Dependency injection.
If this is true then how the previous object values from above DAO
class is reset.
If your bean is stateless there would be no value held by the object, as most of the variable would be method local and not tied to the Instance object (DAO class in this case). However in your case since you have member variable tied to a class
all the classes which acquire this DAO bean would see the same value set to the member variable and this data will be be corrupted and is not recommended.
won't the instance variable hold their values here userId,
userDepartment if the same object is called from multiple class ??
Does stateless means the class cannot have instance variable.
Yes this the exact definition of bean being stateless. As explained above.
does spring internally uses new object() to inject the beans. or it
creates an object of DAO class and makes multiple clones of the
object, which i think is not possible because the DAO class is not
implementing clonnable.
If you have not defined the bean scope, by default spring would assume it is Singleton. The understanding of singleton scope and singleton pattern is different. Spring mimics singleton pattern by providing only instance but this does not stop you from creating new instance (using say new operator).
Your Singleton is not stateless. Userid and Department define the 'state'.
Spring creates one instance using reflection 'newInstance' or a producer function in your configuration.
This one instance is then provided to all objects requesting the DAO.
Your considerations are all valid but not resolved by spring: Since your DAO has a state, it is not properly implemented and results are undefined.
Answer to question 1: It is not reset. Spring won't handle state for you!
Basically (Q2) you are on a dangerous path if you use instance variables in stateless beans. The instance vars need to be stateless themselves, like other DAO singletons.
UPDATE: I want to elaborate on this. The singleton can have a state, but the state is shared between all users of the DAO. This does not strictly require your DAO to be thread safe: If you do not use threads, there is no concurrent use - but the state of a singleton is a shared state: All users of the singleton have the same. If you have two functions like so:
#Component
public class A {
#Autowired
DaoObject singleton;
#Autowired
B another;
public void aFunctionA() {
singleton.userId = "Foo";
System.out.printf("UserId: %s%n", singleton.userId); // prints Foo
another.aFunctionB();
System.out.printf("UserId: %s%n", singleton.userId); // prints Serviceuser
}
}
#Service
public class B {
#Autowired
DaoObject singleton;
public void aFunctionB() {
singleton.userId = "Serviceuser";
}
}
The state of the singleton singleton is shared between all users of the class. If one class changes the state, all other users have to cope with that.
If you are using threads, this adds extra complexity on stateful singletons, as your modifications to state must be thread safe.
It is common practice to keep a singleton immutable after initialization.
On your 4th question: Spring will not clone a Singleton, as described above.
I have a doubt regarding dependency injection,Suppose my controller ,service,dao all are singleton so usually when we create the controller we inject the service as a instance variable of that class, but according to the singleton pattern if our controller is stateless then only we would not face any concurrency issue but here We are declaring the service dependency so it should not be stateless so we have to take care of synchronization?
Please clear this doubt as I am beginner so I hope its natural to have this doubt in mind,I don't know if I am thinking totally wrong.Please help.
All beans in Spring are Singleton by default. This includes any #Controller, #Service, #Repository and others, as well as any xml defined bean.
You could read this and this
From Java basic variable tutorial:
Local Variables Similar to how an object stores its state in fields, a
method will often store its temporary state in local variables. The
syntax for declaring a local variable is similar to declaring a field
(for example, int count = 0;). There is no special keyword designating
a variable as local; that determination comes entirely from the
location in which the variable is declared — which is between the
opening and closing braces of a method. As such, local variables are
only visible to the methods in which they are declared; they are not
accessible from the rest of the class.
If your service and controller are stateless, it's ok to inject one to another.
You should not declare any variable which keeps a state in these classes. final variables are ok.
If all operations are defined in methods and they don't use any variables of the classes, dependency injection that you're doing is totally safe.
That's why you need to use #Autowired when you declare a dependent service. Effectively handing the initialization process to the Spring framework instead of instantiating it yourself. Since Spring only has stateless beans, you're injecting one stateless singleton to another stateless singleton, so there's no need to manage thread manually.
I am experiencing some conceptional difficulty with the scope of some beans referenced in controllers. I have checked a lot of related questions in file and still not sure. Could someone please help me clarify it?
I am numbering the questions or statements as follows to make helper easier to address my problems.
Per my understanding from the the Spring doc, in spring web application,
1) for any controller, annotated with a #Controller, if there is a private field bean, with default bean scope, this field bean will be accessed as the singleton thus susceptible to thread issue;
2) If the field bean is marked as scope=""prototype, this field bean, within this controller, will still behave like a singleton, thus being not-thread safe.
3) To make such a field bean thread safe, we have to make the bean scoped with request or session right?
The following is a simplified example related to this question:
#Controller public Class ControllerA
#Autowired private DefinedBean db;
#RequestMapping("/testPath") public ModelAndView getPathPage(){
this.db.setTitle("abc");
this.db.readReportWithTitle();
....
return new ModelAndView();
}
So in this example,
4) if the DefinedBean is defined through xml configuration with or without explicit scope of prototype, this DefinedBean will have synchronization issue, right?
5) To ensure this DefinedBean to be thread safe, we have to define it explicitly with request or Session.
On the other hand,
6) if we mark the controller itself with a scope of prototype explicitly, will it get rid of the non-thread safe issue with the DefinedBean field? My thought is no, this won't.
7) To make the field thread safe, if we are going to control at the controller level, we need to mark the controller with Scope="Request" as well, right?
Your comments are welcome and appreciated. If you can comment with "Correct" Or "Incorrect" or elaborate further to those numbered (1~7) statements, Myself and possible those who come later will appreciate more.
I think you want to leave the controller be a singleton.
Here is the spring documentation that explains how to bind beans having different scopes.
This is how you would want to define the wired bean:
<bean id="db" class="DefinedBean" scope="request">
<aop:scoped-proxy/>
</bean>
I have looked up to see how the same can be done with annotations only and I have found this.
Basically, you annotate DefinedBean with :
#Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
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.