Can someone explain the usage of the spring #ScopedProxy annotation? I thought it had something to do with session scoped beans, but I'm not quite sure what.
In my usage of scopes, I've used session scoped beans without the #ScopedProxy annotation (or without aop scoped proxies), so I'm really sure how to use it properly.
Section 3.4.4.5 of the spring docs explains it pretty well:
(please note that the following 'userPreferences' bean definition as it stands is incomplete):
<!-- an HTTP Session-scoped bean -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
<!-- a singleton-scoped bean -->
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
From the above configuration it is evident that the singleton bean 'userManager' is being injected with a reference to the HTTP Session-scoped bean 'userPreferences'. The salient point here is that the 'userManager' bean is a singleton... it will be instantiated exactly once per container, and its dependencies (in this case only one, the 'userPreferences' bean) will also only be injected (once!).
This means that the 'userManager' will (conceptually) only ever operate on the exact same 'userPreferences' object, that is the one that it was originally injected with.
This is not what you want when you inject a HTTP Session-scoped bean as a dependency into a collaborating object (typically). Rather, what we do want is a single 'userManager' object per container, and then, for the lifetime of a HTTP Session, we want to see and use a 'userPreferences' object that is specific to said HTTP Session.
Rather what you need then is to inject some sort of object that exposes the exact same public interface as the UserPreferences class (ideally an object that is a UserPreferences instance) and that is smart enough to be able to go off and fetch the real UserPreferences object from whatever underlying scoping mechanism we have chosen (HTTP request, Session, etc.). We can then safely inject this proxy object into the 'userManager' bean, which will be blissfully unaware that the UserPreferences reference that it is holding onto is a proxy.
In our case, when a UserManager instance invokes a method on the dependency-injected UserPreferences object, it will really be invoking a method on the proxy... the proxy will then go off and fetch the real UserPreferences object from (in this case) the HTTP Session, and delegate the method invocation onto the retrieved real UserPreferences object.
That is why you need the following, correct and complete, configuration when injecting request-, session-, and globalSession-scoped beans into collaborating objects:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
After trying out various different options specified here and spring documentation, i have figured out for some reason Spring MVC, is wierdly autowiring controller when you use #Controller annotation and where you have more than one such controller in your webapp. Modified the annotation to #RestController (value="UniqueControllerv1"), the issue is resolved.
Related
I may not fully grasp the concept of beans and services but all my researches lead me to nothing.
In my OSGI project, I got a bundle A that provide a service (called myService).
A bundle B consume this service in a bean (called myBean) that is also exposed as a service.
Beans and service declaration is done in Blueprint.
For now, both bundle A and B are resolved by Karaf and the wiring is ok.
But my bundle B has another bean (called myOtherBean), also exposed as service, that dynamically creates new objects. Those objects (called MyObject) must have a reference on the bean myBean.
How could I pass the reference?
An easy way would be to put the reference in my bean myOtherBean and inject it through the constructor of MyObject. But I am wondering if there could be another way to do that. Some suggested to use the #Inject annotation in MyObject but I can't make it work.
I think passing the service in the constructor is a good way to do this. Using a factory is possible but if you want to create the object in code it is difficult to use a blueprint factory.
You can do it by injecting the blueprint context and retrieving the object from it manually but this is pretty ugly.
Sounds like you have a factory pattern and want to inject the created bean into the declared bean. Correct?
If so see: https://www.ibm.com/developerworks/library/os-osgiblueprint/
<bean id=”accountFactory” class=“org.apache.geronimo.osgi.AccountFactory”>
<argument value=”account factory”/>
</bean>
<bean id=”accountThree”
factory-ref=“accountFactory”
factory-method=“createAccount”>
<argument value=”3”/>
<property name=”description” value=”#3 account”/>
</bean>
This question already has answers here:
How does a ScopedProxy decide what Session to use?
(3 answers)
Closed 7 years ago.
I am trying to use session scope bean in spring mvc with following bean definitions
<bean id="test" class="com.gk.testScope.Test" scope="session">
<property name="name" value="mytest"></property>
<aop:scoped-proxy/>
</bean>
Code for controller
#Controller
public class MyController
{
#Autowired
Test t;
#RequestMapping(value="test1",method=RequestMethod.GET)
public String test1(HttpServletRequest request) {
System.out.println("name"+t.getName());
request.getSession();
return "test1";
}
}
on running above code it prints mytest even before starting any session. Can some one explain what session scope doing here?
Below line of code does not actually create session, it gets the session already created by the servlet container.
request.getSession();
Now comes the important stuff. Bit tricky to get at first if you are new to Spring scopes.
Injecting a singleton bean in another singleton bean is intuitive and makes sense. How about you want to inject a bean which is not Singleton into a Singleton bean? The injection should happen on demand right ? So to configure this, we cant directly inject the bean which is not singleton. We inject a proxy for a non singleton bean, which in turn gets a new bean injected on demand.
<aop:scoped-proxy/>
The above tag helps create a new bean for every session(because the scope is "session") created on the server and injects in the controller on demand.
I am sure someone can explain in much simpler manner. Hope this helps.
The spring framework provides an inversion-of-control coding framework; that means you only has to concern your business logic and write down it as handler function, the spring framework would take care the rest of things and call your handler function.
For example, in a mvc spring framework, the http request handling, http session handling, the beans life-cycle management are all done in spring-framework and you only needed to write the "test1()" function that is called when client hit the URL "/test1".
When client start a HTTP session with spring web server, the framework will create a session scope, and all session scope beans will be created. When client sends a HTTP request, the framework will create a Request scope and all create request level scope beans.
Please see 6.5 Bean scopes from spring reference doc.
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).
With Spring it is possible to inject a list of beans by the interface class like:
#Component
public class Service {
#Autowire
private List<InterfaceType> implementingBeans;
...
}
All defined beans that implement this interface will be present in this List.
The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.
I need to use this mechanism from outside via xml configuration.
<bean id="service" class="...Service">
<property name="implementingBeans">
??? tell spring to create a list bean that resolves all beans of the interfaceType.
</property>
</bean>
Does anyone know how to solve this?
EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.
I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.
Kind regards.
An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".
Controls whether bean properties are "autowired". This is an
automagical process in which bean references don't need to be coded
explicitly in the XML bean definition file, but rather the Spring
container works out dependencies.
[...]
"byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is
raised, and you cannot use byType autowiring for that bean. If there
is none, nothing special happens.
The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.
Your XML would simply look like
<bean id="service" class="...Service" autowire="byType">
</bean>
My original suggested solution made use of SpEL.
In the module that does have Spring dependencies, create a DTO
#Component(value = "beanDTO")
public class BeanDTO {
#Autowire
private List<InterfaceType> implementingBeans;
public List<InterfaceType> getImplementingBeans() {
return implementingBeans;
}
}
and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.
<bean id="service" depends-on="beanDTO" class="...Service">
<property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>
Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.
Following comments on question:
In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with #javax.inject.Inject instead of #Autowired. Similarly, you can use #Named instead of #Component. The documentation has more details.
I'm writing a service registry class. This service registry will scan packages for annotated classes and then populate some internal map. What I need then, is to be able to query for services (by String name) using some method (let's say Object get(String name)). This method will then search internal map for a service with such name and returns instance.
What I'm doing right now, is having this ServiceRegistryBean implement ApplicationContextAware and BeanDefinitionRegistryPostProcessor and a list of Strings (package names) given on construct.
Then, as soon as the bean is constructed, registry post processor kicks in (see note) and the registry class adds the service classes as new beans (singleton, lazy loaded) to the spring bean registry. Then, getting the service instance is as simple as requesting a bean from context, returning singleton instance.
My question is: is there a better way in Spring to do this? I've looked into bean factories, but it does not seem to me the same. Support for auto-wiring and DI in service instances is essential, that's why I want Spring to instantiate it. Also, I like the idea of Spring taking care of singletons.
Note: I've found out, that when I inline the bean creation in <constructor-arg> (that is, bean is not named and is just an instance passed as constructor argument of other bean - in my case, I'm passing registry as a parameter to other constructor), BeanDefinitionRegistryPostProcessor interface methods (namely public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)) is not called at all! I'm quite sure, it is some behavior of Spring I don't know about, but I was not able to find proper documentation for the post-processor.
Thank you for any hints or insights!
Scanning for custom annotations it's already supported, you only need to add a include-filter to <context:component-scan> tag, ie
<context:component-scan base-package="org.example">
<context:include-filter type="annotation" expression="some.Annotation"/>
</context:component-scan>
see http://static.springsource.org/spring/docs/current/spring-framework-reference/html/beans.html#beans-scanning-filters
If you turn on default-lazy-init I suppose that the DI Container is ready to use as Service Locator Registry.
About the note, only root bean definitions are taken into account when looking for BeanFactoryPostProcessors, inner beans are ignored.
Usually, scanning and registering beans is done by BeanDefinitionParsers instead because you known when the beans are registered and beans are visible for tools, like STS Spring Bean Explorer, but using a BeanDefinitionRegistryPostProcessor is correct. The interface ensures that beans are defined before other BeanFactoryPostProcessors run.