I have a problem with spring request scope. It works fine in 99.9% of my calls, because there is almost always a web request available. Unfortunately a few things are done via #Async and here things get tricky.
My desired solution is to replace the bean using #Scope(value = "request" proxyMode = ScopedProxyMode.TARGET_CLASS) with basically the same implementation but using a prototype scope.
I could have both beans inheriting from the same parent and then add the different scopes.
However I have no idea how to make this work. As we have the same Bean, I will get an error that the bean is not unique.
The logic would be to try to create the primary request scope bean and on failure catch the BeanCreationException and replace it with the prototype implementation.
I cannot find a solution with #Primary or named beans here, because in principle, the context of the calling method (somewhere higher in the callstack, i.e. Async or not) decides, whether the bean will be of type request or prototype.
Unfortunately I have not found any real solution for this so far.
Related
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.
I'm learning spring and I'm stuck with the bean lifecycle !
When creating a bean, spring gives us several maners to interact with it. We can use one or all of :
BeanFactoryPostProcessor
BeanPostProcessor#postProcessBeforeInitialization
#PostConstruct
InitializingBean#afterPropertiesSet
#Bean#initMethod
BeanPostProcessor#postProcessAfterInitialization
Spring calls them in the order above
My question is : why all these points of interaction ? and when to use each of them (the use case) ?
A BeanFactoryPostProcessor and a BeanPostProcessor are quite different beast and also apply to different things.
A BeanFactoryPostProcessor will operate on the metadata for a bean (I like to call it the recipe) and will post process that. A well know example is the PropertySourcesPlaceholderConfigurer which will inject/replace all #Value in configuration with the value. A BeanFactoryPostProcessor operates on the metadata and thus before any bean has been created.
The BeanPostProcessor can be applied to a bean and can even replace a bean. Spring AOP uses this quite a lot. An example is the PersistenceExceptionTranslationPostProcessor, when a bean has been created it will pass through this BeanPostProcessor and when it is annotated with #Persistence the bean will be replaced by a proxy. This proxy adds exception translation (i.e. it will convert JpaException and SQLException to the Spring DataAccessException). This is done in a BeanPostProcessor. And can be be done before the init-callbacks are called (the postProcessBeforeInitializationor after they have been called thepostProcessAfterInitialization). The PersistenceExceptionTranslationPostProcessorwill run in thepostProcessAfterInitialization` as it needs to be certain the bean has been initialized.
The ServletContextAwareProcessor will run right after the object has been created to inject the ServletContext as early as possible as the initializing of a bean might depend on it.
The 3 callbacks for initializing a bean are more or less the same but are called in sequence because they have been included in later versions. It starter with only an interface InitializingBean and init-method in xml (later also added to #Bean and the annotation support was added when annotations became a thing.
You need init methods to initialize a bean, you might want to check if all properties have been set (like a required datasource) or you might want to start something. A DataSource (especially a connection pool) is a good example to initialize. After all dependencies have been injected you want to start the pool so it will open the connections. Now as you probably cannot modify the code you want to use the init-method if you control the code you probably want to add #PostConstruct. If you are writing an framework that depends on Spring I would use the InitializingBean.
Next to those 3 init methods you also have the destruction counter-parts. The DisposableBean interface (and destroy-method) and the #PreDestroy annotation. Again when you stop your application you also want to close the connections in your connection pool and you want to probably call the close method on the DataSource. A perfect sample of a destruction callback.
If there's a list of these already available on the web, please link it. I couldn't find any such thing using the Googles.
Request-scoped beans:
javax.servlet.http.HttpServletRequest
Session-scoped beans:
javax.servlet.http.HttpSession
Well it really depends on what you've told Spring to create, but you'd see this in a default setup.
REQUEST:
for(String key : Collections.list(request.getAttributeNames())) {
System.out.println( key );
}
RESULT:
org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER
org.springframework.web.servlet.DispatcherServlet.CONTEXT
org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER
org.springframework.web.servlet.HandlerMapping.bestMatchingPattern
org.springframework.web.servlet.DispatcherServlet.OUTPUT_FLASH_MAP
org.springframework.web.servlet.DispatcherServlet.FLASH_MAP_MANAGER
org.springframework.core.convert.ConversionService
org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE
org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping
org.springframework.web.servlet.HandlerMapping.uriTemplateVariables
org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER
SESSION:
for(String key : Collections.list(session.getAttributeNames())) {
System.out.println( key );
}
RESULT:
(empty)
Autowiring happens once, after the object creation, and this is a main thing to keep in mind when reasoning about autowiring and different scopes.
About your question, there's in fact no issue when it comes to injecting longer living beans inside a short-lived beans. Its only important that you're aware of it and that it fits your semantic.
Other way around is a bit trickier. So injecting shorter lived beans, inside a longer lived beans. The proper way for doing this is leaning on proxies. If you're injecting a request-scoped bean inside a session-scoped bean, and if the request-scoped bean is proxied, than the proxy will be created only once, but will create a request bean on each request.
Its a simplification of what is described in the docs and available at http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-scopes-other-injection
You can autowire anything that Spring can build. Whether or not you should is another matter.
For example, it is utterly senseless to autowire a bean with Step scope (from batch processing) to a request scoped bean.
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).
How can I inject dependencies into a deserialized bean?
Some of my Spring beans should be serialized during the render-response phase of our JSF application, and then deserialized at the beginning of the next request. Some of those beans have dependencies which are scoped to the request. If I configure the dependencies with the scoped proxy ("<aop:scoped-proxy>"), I can't serialize my dependent beans - the proxy isn't serializable.
So right now we do it by declaring the appropriate member variables of the serialized bean classes as transient, and then calling context.getAutowireCapableBeanFactory().configureBean(bean, name) just after deserializing the beans - but this sucks, because the bean's initializer is called again. (As for other dependencies that are in the same scope, are not transient, and are deserialized, I'm not even sure why they don't get overwritten by configureBean, but I don't think they are.)
What's better? Should I just get the bean definition, loop through it, find the dependencies that are scoped to the request, and then call getBean(name) on the context?
(BTW, I'm not sure it makes a difference, but we are using Spring kind of weirdly. We instantiate a new ClassPathXmlApplicationContext for each non-posted-back HTTP request, rather than a single WebApplicationContext. Upon postback, we deserialize the beans. So when I say "scoped to the request", I'm lying; these beans are actually singleton-scoped. I'd like to use the WebApplicationContext and the more sane scoping with it, but as far as I can tell, that's orthogonal to our problem at the moment.)
It makes all the difference - I've been using spring with JSF for quite a long time and hadn't had any serialization problems. The way to go is simply define the following in your faces-config.xml:
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
This integrates spring with JSF by providing spring beans (using the request and session spring scopes) to JSF pages.
So, I'd advice for changing your approach drastically so that you aren't bug with such problems in the future.