How does Spring autowire session scoped beans? - java

I'm currently working with session objects. In service layer I'm autowiring session scoped bean. And I wonder how Spring is able to do this? And more interesting part, even if I use final keyword and use constructor injection, Spring is still able to autowire the object.
#Service
public class SomeServiceImpl implements SomeService {
private final UserSessionDetails userSessionDetails;
#Autowired
public SomeServiceImpl(final UserSessionDetails userSessionDetails) {
this.userSessionDetails = userSessionDetails;
}
}
And my other question is; Is it good practice the using session objects in Service layer? Or am I free to use these objects in Controller and Service layers?

I wonder how Spring is able to do this?
SomeServiceImpl is a singleton, so it should be assembled at startup. Assembling a bean means injecting all required dependencies to it. Although some candidates may have the scope different from the singleton scope, they still have to be provided. For such beans, Spring creates proxies. A proxy is basically a meaningless wrapper until some context comes.
if I use final keyword and use constructor injection, Spring is still able to autowire the object.
Spring supports constructor-based injection. It examines the signature and looks up candidates to inject; the modifiers of a field don't matter.
Is it good practice the using session objects in Service layer? Or am I free to use these objects in Controller and Service layers?
As long as the service is web-oriented and session-concerned, you are free to inject session-scoped beans to it.

You are autowiring by constructor, so the usage of word final does not change anything in this case. By annotating UserSessionDetails as session scoped bean, and injecting it into SomeServiceImpl spring generates a proxy. Any call from your service, is being delegated into UserSessionDetails bean.

Related

Do multiple thread request share same singleton beans in Spring?

I have been trying to understand spring beans. As per my understanding, by default all beans are singleton and a singleton bean with lazy-init property set to true is created when it is first requested and singleton bean with lazy-init property set to false is created when the application context is created.
So, in an application, when a user request comes in ( where each request is a separate thread), do all these threads share the same singleton beans when requested within the program/class?
Yes, if the bean is created with default scope, the bean is shared across threads. However, another scope can be used to achieve the behaviour you mentioned.
See: https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch04s04.html?
Yes, by default (scope == 'singleton'), all threads will share the same singleton bean. There are two other bean scopes, session and request, that may be what you're looking for. The request scope creates a bean instance for a single HTTP request while session scope maintains a unique bean for each HTTP Session.
For a list and description of all of the Spring bean scopes, check out: Spring bean scopes
The best way to understand this is to understand how #Autowired annotation works.
Or in other words to understand "Spring Dependency Injection".
You said, "
by default all beans are singleton
We use #Autowired when injecting one layer into another between two layers.
If exemplify: Suppose, I want to inject UserService UserController. UserService is a Singleton bean. Creates an instance from UserService and Stores its cache. When we want to inject this service with #Autowired annotation. This annotation brings the UserService stored in the cache.
In this way, Even if we do this inject operation in many classes.#Autowired inject an instance of UserService with singleton bean instead of dealing with one UserService at each time. It saves us a big burden.
This is the fundamental working logic of Spring Singleton Bean.
Also, Spring Ioc Container manages this whole process.

Inject HttpServletRequest into Controller

As I know per default are controllers in Spring MVC singletons. HttpServletRequest passed offen to the controller handler method. And its ok, while HttpServletRequest is request-scoped, but I see often HttpServletRequest gets #Autowired into the controller field, like this:
#Controller("CMSProductComponentController")
#RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
#Autowired
private HttpServletRequest request;
}
Could be this a problem? And more general question: What happens if inject a reqeust-scoped component into a singleton?
No, for HttpServletRequest it will not be a problem and it shouldn't for other request scoped beans. Basically, Spring will generate a proxy HttpServletRequest that wraps some kind of ObjectFactory (RequestObjectFactory for HttpServletRequest) (YMMV) that knows how to retrieve the actual instance. When you use any of the methods of this proxy, they will delegate to that instance.
What's more, this is done lazily, so it won't fail at initialization. It will however fail if you try to use the bean when there is no request available (or if you haven't registered the RequestScope).
The following is in response to the comments and to clarify in general.
Regarding the proxy-mode attribute of #Scope or the XML equivalent, the default is ScopedProxyMode.NO. However, as the javadoc states
This proxy-mode is not typically useful when used with a non-singleton
scoped instance, which should favor the use of the INTERFACES or
TARGET_CLASS proxy-modes instead if it is to be used as a dependency.
With request scoped beans, this proxy-mode value will not work. You'll need to use INTERFACES OR TARGET_CLASS depending on the configuration you want.
With scope set to request (use the constant WebApplicationContext.SCOPE_REQUEST), Spring will use RequestScope which
Relies on a thread-bound RequestAttributes instance, which can be
exported through RequestContextListener, RequestContextFilter or
DispatcherServlet.
Let's take this simple example
#Component
#Scope(proxyMode = ScopedProxyMode.INTERFACES, value = WebApplicationContext.SCOPE_REQUEST)
public class RequestScopedBean {
public void method() {}
}
...
#Autowired
private RequestScopedBean bean;
Spring will generate two bean definitions: one for your injected bean, a singleton, and one for the request scoped bean to be generated on each request.
From those bean definitions, Spring will initialize the singleton as a proxy with the types of your target class. In this example, that is RequestScopedBean. The proxy will contain the state it needs to produce or return the actual bean when it is needed, ie. when a method is called on the proxy. For example, when
bean.method();
is called.
This state is basically a reference to the underlying BeanFactory and the name of the request-scoped bean definition. It will use these two to generate a new bean and then call method() on that instance.
The documentation states
The Spring IoC container manages not only the instantiation of your
objects (beans), but also the wiring up of collaborators (or
dependencies). If you want to inject (for example) an HTTP request
scoped bean into another bean, you must inject an AOP proxy in place
of the scoped bean. That is, you need to inject a proxy object that
exposes the same public interface as the scoped object but that can
also retrieve the real, target object from the relevant scope (for
example, an HTTP request) and delegate method calls onto the real
object.
All eagerly loaded request scoped beans, if implemented correctly, will be proxies. Similarly, request scoped beans that aren't eagerly loaded will either be proxies themselves or be loaded through a proxy. This will fail if there is no HttpSerlvetRequest bound to the current thread. Basically, a proxy is necessary somewhere in the bean dependency chain for request scoped beans.
What happens if inject a reqeust-scoped component into a singleton?
Try it and you'll get a BeanCreationException¹ during application context initialization. The error message clearly explains why this doesn't happen with HttpServletRequest:
Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;
So obviously HttpServletRequest is a scoped proxy. If you want to use beans of smaller scopes in singletons they have to be proxies. The documentation elaborates about smaller scoped dependencies in Scoped beans as dependencies.
[1]: unless you didn't change the default behaviour for proxyMode, which is NO or try to inject it with #Lazy. The latter might result into a valid application context but might lead to request scoped beans acting like singletons (e.g. if a request scoped bean is injected into a singleton).

best practices of using bean scopes in spring mvc application

I have seen it written at many places that DAO and Service classes of a spring application should be singleton scoped.
In my application I have the following service class
#Service
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDAO customerDAO;
.......
parameterised methods only....
}
and a DAO class
#Repository
public class CustomerDAOImpl implements CustomerDAO {
#Autowired
private SessionFactory sessionFactory;
...............
parameterised methods only....
}
Since I haven't defined any scope, the default scope is singleton.So both the CustomerService and CustomerDAO will be instantiated only once per the container.Also the DAO class will be autowired to the Service class only once at the beginning.Since it is going to be a heavy request web application, that means (OR does that mean ?) hundreds of threads are going to use the same instances of both the classes.
Then how thread safety is guaranteed in this case ?
And what about the scope of hibernate sessionfactory bean defined in the xml ?
I am very much confused about the bean scopes and thread safety in a spring mvc application. Springsource documentation doesn't clearly explain these for a web application.
Could anyone please explain me the best practises of using bean scopes(for DAO, Service, Controller and other beans) for a heavy request web application ?
Any link which explains these woulb be grateful for me.
Thanks for your suggestions in advance.
As long as your service and DAO singletons do not hold state (don't hold instance variables - other beans excepted - manipulated inside methods), there is no problem regarding thread safety. Regarding session factory, the default hibernate session scope in spring web-app is based on the "one hibernate session per request" pattern, which means that you will have one session for each http request (thread) and so no reason to worry about concurrency neither.

#Inject only working for POJOs created by CDI container?

I just want to confirm that I fully understood the prerequisites for CDI to work. If I have a class A:
public class A {
#Inject private B b;
}
Now when I instantiate this class using:
A a = new A();
In that case, A.b will be null.
But if I define in another class a member:
#Inject A a;
and later use a, a.b will be correctly populated?
Does CDI only work if the class requiring an injection was also created by CDI container? Or what am I missing if injections turn out to be null while creating a POJO using ordinary instantiation with new (yes, I got beans.xml in place)?
Does CDI only work if the class requiring an injection was also
created by CDI container?
Yes, that's pretty much it. The lifecycle of a ManagedBean is controlled by the container and should never be instantiated with the new keyword (BTW: the same is true for EJBs & Spring beans). If you need to create a new ManagedBean you will probably want to use a producer method.
While others have stated correctly that for the most part DI containers will not inject dependencies into bean that they did not instantiate this is not entirely true.
Spring has a wonderful feature that will autowire the bean when you create it using new A().
You just have to use AspectJ and mark your bean with the #Configurable annotation.
#Configurable
public class A {
#Inject private B b;
}
Its actually kind of an awesome feature cause you can do Active Record style POJO's while still honoring your DI (its in fact how Spring Roo does it).
You should also know that with Spring you can autowire a bean programmatically after its been instantiated with the AutowireCapableBeanFactory. This is how it typically autowires JUnit Test Case Classes because JUnit creates the test case classes.
Yes Spring is not CDI but in theory you could write your own #Configurable for CDI or there is probably a CDI way of doing the above.
That being said the above is sort of a sophisticated feature (and kind of a hack) and as #JanGroth mentioned understaning the lifecycle bean management of the container is critical whether its CDI, Spring, Guice etc.
You may use BeanProvider.injectFields(myObject); from Apache DeltaSpike.
Yes, #Inject works only inside a container because it is done using interceptors on method calls. When the container creates a bean it wrappes it in interceptors which perform injection, and in the case of instantiation using new no interceptors will be called during bean method invocation, and there will be no injection.
Here's the conditions needed for a class to be a managed bean (and hence, for the #Inject annotation to work on its fields/methods):
http://docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html

Spring session-scoped beans (controllers) and references to services, in terms of serialization

a standard case - you have a controller (#Controller) with #Scope("session").
classes put in the session usually are expected to implement Serializable so that they can be stored physically in case the server is restarted, for example
If the controller implements Serializable, this means all services (other spring beans) it is referring will also be serialized. They are often proxies, with references to transaction mangers, entity manager factories, etc.
It is not unlikely that some service, or even controller, hold a reference to the ApplicationContext, by implementing ApplicationContextAware, so this can effectively mean that the whole context is serialized. And given that it holds many connections - i.e. things that are not serializable by idea, it will be restored in corrupt state.
So far I've mostly ignored these issues. Recently I thought of declaring all my spring dependencies transient and getting them back in readResolve() by the static utility classes WebApplicationContextUtils and such that hold the request/ServletContext in a ThreadLocal. This is tedious, but it guarantees that, when the object is deserialized, its dependencies will be "up to date" with the current application context.
Is there any accepted practice for this, or any guidelines for serializing parts of the spring context.
Note that in JSF, managed beans (~controllers) are stateful (unlike action-based web frameworks). So perhaps my question stands more for JSF, than for spring-mvc.
In this presentation (around 1:14) the speaker says that this issue is resolved in spring 3.0 by providing a proxy of non-serializable beans, which obtains an instance from the current application context (on deserialization)
It appears that bounty didn't attract a single answer, so I'll document my limited understanding:
#Configuration
public class SpringConfig {
#Bean
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
MyService myService() {
return new MyService();
}
#Bean
#Scope("request")
public IndexBean indexBean() {
return new IndexBean();
}
#Bean
#Scope("request")
public DetailBean detailBean() {
return new DetailBean();
}
}
public class IndexBean implements Serializable {
#Inject MyService myService;
public void doSomething() {
myService.sayHello();
}
}
public class MyService {
public void sayHello() {
System.out.println("Hello World!");
}
}
Spring will then not inject the naked MyService into IndexBean, but a serializable proxy to it. (I tested that, and it worked).
However, the spring documentation writes:
You do not need to use the <aop:scoped-proxy/> in conjunction with beans that are scoped as singletons or prototypes. If you try to create a scoped proxy for a singleton bean, the BeanCreationException is raised.
At least when using java based configuration, the bean and its proxy can be instantiated just fine, i.e. no Exception is thrown. However, it looks like using scoped proxies to achieve serializability is not the intended use of such proxies. As such I fear Spring might fix that "bug" and prevent the creation of scoped proxies through Java based configuration, too.
Also, there is a limitation: The class name of the proxy is different after restart of the web application (because the class name of the proxy is based on the hashcode of the advice used to construct it, which in turn depends on the hashCode of an interceptor's class object. Class.hashCode does not override Object.hashCode, which is not stable across restarts). Therefore the serialized sessions can not be used by other VMs or across restarts.
I would expect to scope controllers as 'singleton', i.e. once per application, rather than in the session.
Session-scoping is typically used more for storing per-user information or per-user features.
Normally I just store the 'user' object in the session, and maybe some beans used for authentication or such. That's it.
Take a look at the spring docs for configuring some user data in session scope, using an aop proxy:
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection
Hope that helps
I recently combined JSF with Spring. I use RichFaces and the #KeepAlive feature, which serializes the JSF bean backing the page. There are two ways I have gotten this to work.
1) Use #Component("session") on the JSF backing bean
2) Get the bean from ELContext when ever you need it, something like this:
#SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName);
}
After trying all the different alternatives suggested all I had to do was add aop:scoped-proxy to my bean definition and it started working.
<bean id="securityService"
class="xxx.customer.engagement.service.impl.SecurityContextServiceImpl">
<aop:scoped-proxy/>
<property name="identityService" ref="identityService" />
</bean>
securityService is injected into my managedbean which is view scoped. This seems to work fine. According to spring documentation this is supposed to throw a BeanCreationException since securityService is a singleton. However this does not seems to happen and it works fine. Not sure whether this is a bug or what the side effects would be.
Serialization of Dynamic-Proxies works well, even between different JVMs, eg. as used for Session-Replication.
#Configuration public class SpringConfig {
#Bean
#Scope(proxyMode = ScopedProxyMode.INTERFACES)
MyService myService() {
return new MyService();
}
.....
You just have to set the id of the ApplicationContext before the context is refreshed (see: org.springframework.beans.factory.support.DefaultListableBeanFactory.setSerializationId(String))
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// all other initialisation part ...
// before! refresh
ctx.setId("portal-lasg-appCtx-id");
// now refresh ..
ctx.refresh();
ctx.start();
Works fine on Spring-Version: 4.1.2.RELEASE

Categories

Resources