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).
Related
I noticed that the #PreDestroy hooks of my prototype scoped Spring beans were not getting executed.
I have since read here that this is actually by design. The Spring container will destroy singleton beans but will not destroy prototype beans. It is unclear to me why. If the Spring container will create my prototype bean and execute its #PostConstruct hook, why will it not destroy my bean as well, when the container is closed? Once my Spring container has been closed, does it even make sense to continue using any of its beans? I cannot see a scenario where you would want to close a container before you have finished with its beans. Is it even possible to continue using a prototype Spring bean after its container has been closed?
The above describes the puzzling background to my primary question which is: If the Spring container is not destroying prototype beans, does that mean a memory leak could occur? Or will the prototype bean get garbage-collected at some point?
The Spring documentations states:
The client code must clean up prototype-scoped objects and release
expensive resources that the prototype bean(s) are holding. To get the
Spring container to release resources held by prototype-scoped beans,
try using a custom bean post-processor, which holds a reference to
beans that need to be cleaned up.
What does that mean? The text suggests to me that I, as the programmer am responsible for explicitly (manually) destroying my prototype beans. Is this correct? If so, how do I do that?
For the benefit of others, I will present below what I have gathered from my investigations:
As long as the prototype bean does not itself hold a reference to another resource such as a database connection or a session object, it will get garbage collected as soon as all references to the object have been removed or the object goes out of scope. It is therefore usually not necessary to explicitly destroy a prototype bean.
However, in the case where a memory leak may occur as described above, prototype beans can be destroyed by creating a singleton bean post-processor whose destruction method explicitly calls the destruction hooks of your prototype beans. Because the post-processor is itself of singleton scope, its destruction hook will get invoked by Spring:
Create a bean post processor to handle the destruction of all your prototype beans. This is necessary because Spring does not destroy prototype beans and so any #PreDestroy hooks in your code will never get called by the container.
Implement the following interfaces:
1.BeanFactoryAware
This interface provides a callback method which receives a Beanfactory object. This BeanFactory object is used in the post-processor class to identify all prototype beans via its BeanFactory.isPrototype(String beanName) method.
2. DisposableBean
This interface provides a Destroy() callback method invoked by the Spring container. We will call the Destroy() methods of all our prototype beans from within this method.
3. BeanPostProcessor
Implementing this interface provides access to post-process callbacks from within which, we prepare an internal List<> of all prototype objects instantiated by the Spring container. We will later loop through this List<> to destroy each of our prototype beans.
3. Finally implement the DisposableBean interface in each of your prototype beans, providing the Destroy() method required by this contract.
To illustrate this logic, I provide some code below taken from this article:
/**
* Bean PostProcessor that handles destruction of prototype beans
*/
#Component
public class DestroyPrototypeBeansPostProcessor implements BeanPostProcessor, BeanFactoryAware, DisposableBean {
private BeanFactory beanFactory;
private final List<Object> prototypeBeans = new LinkedList<>();
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanFactory.isPrototype(beanName)) {
synchronized (prototypeBeans) {
prototypeBeans.add(bean);
}
}
return bean;
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
#Override
public void destroy() throws Exception {
synchronized (prototypeBeans) {
for (Object bean : prototypeBeans) {
if (bean instanceof DisposableBean) {
DisposableBean disposable = (DisposableBean)bean;
try {
disposable.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
prototypeBeans.clear();
}
}
}
Your answer is great. I'd also like to share some notes on an alternative solution that allows prototype members which are natively managed by the Spring IoC container lifecycle through the use of the inner beans.
I recently wrote an answer to a separate question on inner beans. Inner beans are created by assigning bean property values as BeanDefinition objects. Bean definition property values are automatically resolved to (inner) instances (as managed singleton beans) of the bean that they define.
The following XML context configuration element can be used to create distinct autowireable ForkJoinPool beans for each reference which will be managed (#PreDestroy will be called on context shutdown):
<!-- Prototype-scoped bean for creating distinct FJPs within the application -->
<bean id="forkJoinPool" class="org.springframework.beans.factory.support.GenericBeanDefinition" scope="prototype">
<property name="beanClass" value="org.springframework.scheduling.concurrent.ForkJoinPoolFactoryBean" />
</bean>
This behavior is contingent upon the reference being assigned as a property value of a bean definition, though. This means that #Autowired- and constructor-injection do not work with this by default, since these autowiring methods resolve the value immediately rather than using the property value resolution in AbstractAutowireCapableBeanFactory#applyPropertyValues. Autowiring by type will also not work, as type-resolution will not propagate through beans that are BeanDefinitions to find the produced type.
This method will only work if either of the two conditions are true:
The dependent beans are also defined in XML
Or if the autowire mode is set to AutowireCapableBeanFactory#AUTOWIRE_BY_NAME
<!-- Setting bean references through XML -->
<beans ...>
<bean id="myOtherBean" class="com.example.demo.ForkJoinPoolContainer">
<property name="forkJoinPool" ref="forkJoinPool" />
</bean>
</beans>
<!-- Or setting the default autowire mode -->
<beans default-autowire="byName" ...>
...
</beans>
Two additional changes could likely be made to enable constructor-injection and #Autowired-injection.
Constructor-injection:
The bean factory assigns an AutowireCandidateResolver for constructor injection. The default value (ContextAnnotationAutowireCandidateResolver) could be overridden (DefaultListableBeanFactory#setAutowireCandidateResolver) to apply a candidate resolver which seeks eligible beans of type BeanDefinition for injection.
#Autowired-injection:
The AutowiredAnnotationBeanPostProcessor bean post processor directly sets bean values without resolving BeanDefinition inner beans. This post processor could be overridden, or a separate bean post processor could be created to process a custom annotation for managed prototype beans (e.g., #AutowiredManagedPrototype).
If I create a bean annotated with #RequestScoped I expect that it will instantiate a new proxy instance with each new request.
From the other hand each request is associated with its own thread.
My question is: will CDI reuse previously created proxy object of my bean/service if the new request reuses previously created thread from a pool?
First of all, it's important to understand that client proxy object != bean instance (or contextual instance if we want to follow the spec wording). For #RequestScoped a new bean instance is always created for each request. However, #RequestScoped is a normal scope, which means that a client proxy is injected (and this proxy delegates to the bean instance).
Now back to your question to client proxy object - the strategy is implementation-specific. The spec states that a container might instantiate one client proxy object per bean and share it between multiple injection points. But it's not required (see also this documentation). Reference implementation (Weld, WildFly, GlassFish, etc.) DOES share client proxy objects. But again, we're speaking about client proxies, not bean instances.
WRT thread association - request context is associated with one thread but when the request ends the context is destroyed (incl. all bean instances) and the thread is dissociated.
Need some help with Spring autowiring, and scopes.
Here is the basic app structure:
I have an CustomHttpClient, annotated as #Component, and also pulling some config-related properties from application.properties file (via #Value annotation).
CustomHttpClient is used by several services in my application. Whenever I'm using the CustomHttpClient, I autowire an instance of that via:
#Autowired
private CustomHttpClient httpClient;
I use interceptor to modify some of the variables inside CustomHttpClient, like so:
public class MyInterceptor extends HandlerInterceptorAdapter {
#Autowired CustomHttpClient httpClient;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
httpClient.setSomeProperty(newValue);
...
Now, here is the problem. If I have everything set up as described above, then whenever I change any setting of the CustomHttpClient via interceptor, that new value is persisted for all other clients, as long as VM is running. So when I run httpClient.setSomeProperty() - that setting is now permanently saved. Even if I connect to the application from another client.
Basically what I need to have are two things:
Still being able to override default settings of the CustomHttpClient via interceptor (request interceptor, configured via ).
Make sure a new instance of CustomHttpClient is created for every request (after the interceptor does its' magic).
I tried changing the scope of CustomHttpClient to #Scope("prototype"), but that way I can no longer change settings of CustomHttpClient with an interceptor.
By default when you use #Autowired spring bean scope is singleton. That means spring injects the same singleton object where ever you use #Autowired. By making scope prototype you are instructing Spring to create new objects for each #Autowired injection, and so in your interceptor will have its own copy of HttpClient and cant see other HttpClient objects.
So better approach is use the singleton scope, Use request attributes or threadlocal to carry around your custom properties down the request thread. ie instead of modifying HttpClient properties in interceptor, just set some request attributes or threadlocals and handle these custom settings within CustomHttpClient class methods.
If your interceptor is only addding some properties then using thread local should be a better option. You can call ThreadLocal.set(custom Map) and use it wherever you want for the running thread and when your program is going to leave your controller you can call ThreadLocal.Unset which will clear the value stored.
This way you wont need a new instance of HttpcLient everytime, also a new instance every time would be a serious flaw. And you will be able to use your custom map anywhere you want in the running thread.
All beans declared in the Spring container enther by XML or by annotation support are by default singletons. If you inject a bean with scope set to prototype into a singleton e.g. a controller it will inject it only once. There is a way to achieve this goal. This is how you should declare a bean scoped as a prototype. This means that the container will always give you a new instance each time this bean is called upon from the container.
<bean id="shoppingCart" class="example.ShoppingCart" scope="request">
<aop:scoped-proxy />
</bean>
I want to inject the current user using #Inject #Current User across all layers (i.e. web layer, EJB layer). In order to do this, I have the following CDI Producer method:
#Named
#SessionScoped
public class UserController {
#Resource SessionContext sessionContext;
#EJB UserDao userDao;
#Produces #Current
public User getCurrentUser() {
String username = sessionContext.getCallerPrincipal().getName();
User user = userDao.findByUsername(username);
}
}
#Qualifier
#Target({TYPE, METHOD, PARAMETER, FIELD})
#Retention(RUNTIME)
public #interface Current{}
Now, I want to inject the current user into an EJB stateless session bean as follows:
#Stateless
public class SomeBackendService {
#Inject #Current
private User user;
}
My question: Is the current user object always re-injected after the session changes, because the dependencies of a stateless session bean are normally injected once at creation time and the bean may be pooled and used across different sessions?
Although I haven't tried this exact situation, in CDI beans are normally not re-injected. Instead, a proxy is injected that is aware of its context.
Via this mechanism, it's possible to inject say a session scoped bean in an application scoped bean. Every user of the application scoped bean goes to the same bean and the same proxy, but the proxy will then dynamically resolve calls on it to a different bean for each user.
So even though the scope of #Stateless is basically 'application', it would be possible that the proxy that represents User in your `SomeBackendService' still delegates to the correct session scoped version.
p.s.
If with layers you actually mean modules as in web and EJB modules that are part of an EAR, it's going to be a little bit more complicated, as CDI doesn't always works as expected between modules (especially in JBoss AS). This is partly due to the ambiguity of what an 'application' and thus the application scope is within an EAR.
Yes, to each business method called the container will be re-injected all dependencies of your SLSB. Here is text that guarantees this in EJB 3.1 specification:
"If a session bean makes use of dependency injection, the container injects these references after the bean instance is created, and before any business methods are invoked on the bean instance." - Section 4.3.2
I had this doubt too and I posted a question explaining this situation
here
By design, your stateless session bean should not have a state "User", it's stateless by all means.
If you want your EJB to have states, then use #Stateful instead.
We have some JavaEE5 stateless EJB bean that passes the injected EntityManager to its helpers.
Is this safe? It has worked well until now, but I found out some Oracle document that states its implementation of EntityManager is thread-safe. Now I wonder whether the reason we did not have issues until now, was only because the implementation we were using happened to be thread-safe (we use Oracle).
#Stateless
class SomeBean {
#PersistenceContext
private EntityManager em;
private SomeHelper helper;
#PostConstruct
public void init(){
helper = new SomeHelper(em);
}
#Override
public void business(){
helper.doSomethingWithEm();
}
}
Actually it makes sense.. If EntityManager is thread-unsafe, a container would have to do
inercept business()
this.em = newEntityManager();
business();
which will not propagate to its helper classes.
If so, what is the best practice in this kind of a situation? Passing EntityManagerFactory instead of EntityManager?
EDIT: This question is very interesting so if you are interested in this question, you probably want to check out this one, too:
EDIT: More info.
ejb3.0 spec
4.7.11 Non-reentrant Instances
The container must ensure that only one
thread can be executing an instance at
any time. If a client request arrives
for an instance while the instance is
executing another request, the
container may throw the
javax.ejb.ConcurrentAccessException to
the second client[24]. If the EJB 2.1
client view is used, the container may
throw the java.rmi.RemoteException to
the second request if the client is a
remote client, or the
javax.ejb.EJBException if the client
is a local client.[25] Note that a
session object is intended to support
only a single client. Therefore, it
would be an application error if two
clients attempted to invoke the same
session object. One implication of
this rule is that an application
cannot make loopback calls to a
session bean instance.
And,
4.3.2 Dependency Injection
A session bean may use dependency injection
mechanisms to acquire references to
resources or other objects in its
environment (see Chapter 16,
“Enterprise Bean Environment”). If a
session bean makes use of dependency
injection, the container injects these
references after the bean instance is
created, and before any business
methods are invoked on the bean
instance. If a dependency on the
SessionContext is declared, or if the
bean class implements the optional
SessionBean interface (see Section
4.3.5), the SessionContext is also injected at this time. If dependency
injection fails, the bean instance is
discarded. Under the EJB 3.0 API, the
bean class may acquire the
SessionContext interface through
dependency injection without having to
implement the SessionBean interface.
In this case, the Resource annotation
(or resource-env-ref deployment
descriptor element) is used to denote
the bean’s dependency on the
SessionContext. See Chapter 16,
“Enterprise Bean Environment”.
I used a similar pattern, but the helper was created in #PostConstruct and the injected entity manager was passed in the constructor as parameter. Each EJB instance had its own helper and thread-safety was guaranteed then.
I also had a variant were the entity manager was not injected (because the EJB wasn't using it altogether), so the helper has to look it up with InitialContext. In this case, the Persistence context must still be "imported" in the parent EJB with #PersistenceContext:
#Stateless
#PersistenceContext(name="OrderEM")
public class MySessionBean implements MyInterface {
#Resource SessionContext ctx;
public void doSomething() {
EntityManager em = (EntityManager)ctx.lookup("OrderEM");
...
}
}
But it's actually easier to inject it (even if the EJB doesn't use it) than to look it up, especially for testability.
But to come back to your main question, I think that the entity manager that is injected or looked up is a wrapper that forwards to the underlying active entity manager that is bound to the transaction.
Hope it helps.
EDIT
The section § 3.3 and § 5.6 in the spec cover a bit the topic.
I've been using helper methods and passed the EntityManager there, and it is perfectly OK.
So I'd recommend either passing it to methods whenever needed, or make the helper a bean itself, inject it (using #EJB) and inject the EntityManager there as well.
Well, personally, I wouldn't like to have to pass the Entity Manager to all my POJOs in my constructors or methods. Especially for non-trivial programs where the number of POJOs is large.
I would try to create POJOs/HelperClasses that deal with the Entities returned by the EntityManager, instead of using the entitymanager directly.
If not possible, I guess I'd create a New EJB Bean.