I am exposing a bean that is not thread safe via Spring's http invoker. What I want is that every remote call should get a new instance of the bean. I started by setting the scope to prototype for the bean that I am exposing in the Dispatcher servlet XML. But it still seemed to create only one instance. So all client threads were concurrently accessing the same bean instance.
Next I also set the scopr to prototype for HttpInvokerProxyFactoryBean in the client spring-config.xml. But even then I see a single instance of the bean being returned.
Any ideas on what I am doing wrong? Or has anyone else faced this problem.
Thanks in advance.
Here are the relevant snippets
DispatcherServlet-servlet.xml
<bean id="fuBeanImpl" class="com.fubar.FuBeanImpl" scope="prototype">
</bean>
<bean id="fuBeanService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="fuBeanImpl"/>
<property name="serviceInterface" value="com.fubar.FuBean"/>
</bean>
spring-config.xml
<bean id="fuBeanService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" scope="prototype">
<property name="serviceUrl">
<value>http://fubar/fuBeanService</value>
</property>
<property name="serviceInterface">
<value>com.fubar.FuBean</value>
</property>
<property name="httpInvokerRequestExecutor">
<bean class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"/>
</property>
</bean>
There is another current question Prototype Scope not working about an almost identical problem.
Both of these solutions should work here also:
Tight coupling to the
ApplicationContext and looking up the
Bean manually
Lookup Method Injection via
CGLib (by yours truly)
This is because your HttpInvokerServiceExporter bean is still a singleton, and it has a reference to the prototype-scoped fuBeanImpl bean. So the exporter gets a single instance of FuBeanImpl and never asks for a new one. This is the problem with singleton-scoped beans referring to on-singleton-scoped beans - the reference "collapses" the prototype, effectively.
You need to make HttpInvokerServiceExporter a prototype-scoped bean also, although this might have side-effects. For example, you haven't told us what is referring to the HttpInvokerServiceExporter - probably a url-mapping definition somewhere?
edit: Since you've clarified that you're using a SimpleUrlhandlerMapping, then what you can do is to inject that with the name of the handler bean, rather than a direct bean reference to it. This means that the handler bean (i.e. the fuBeanService bean) can be a prototype, even though the SimpleUrlhandlerMapping is a singleton.
Related
Information part:
Application uses spring context.xml for declaring spring beans.
I need inject prototype bean into singleton every time of prototype using (sounds trivial). This part has is clear for me on flow & implementation side.
Example of declaring bean is:
<bean id="entryNumberHelper" class="path.toMyBean.EntryNumberHelper"
lazy-init="true" scope="prototype">
<constructor-arg name="orderEntryGroup" value="dynamicValueNewForDifferentPrototypes"/>
<property name="modelService" ref="modelService"/>
</bean>
Questions:
How to describe in xml creation of parameterized prototype (only singleton where prototype should be injected knows about orderEntryGroup parameter)?
How to inject one in dynamic way?
P.S. - workaround
I can create one more method that can be used for prototype building (creation and tuning) but I dislike redundant code and hoping for elegant solution hidden in spring framework.
I have legacy project with a lot of beans in several contexts. Seems like there are circular dependencies between beans and that's why most of contexts has default-lazy-init set to true.
I need export some bean via RMI, so I have folowing declarations in the context:
<bean id="partnershipPluginService" class="com.otr.sufd.services.security.PartnershipPluginServiceImpl" lazy-init="false">
<property name="selectionService" ref="selectionService"/>
<property name="editObjectService" ref="editObjectService"/>
<property name="securityFieldsService" ref="securityFieldsService"/>
<property name="cryptoSettingsService" ref="cryptoSettingsService"/>
<property name="authenticationService" ref="systemAuthenticationService"/>
<property name="configurationManager" ref="serverConfigurationManager"/>
<property name="lifeCycleDefService" ref="lifeCycleDefService"/>
</bean>
<bean class="org.springframework.remoting.rmi.RmiServiceExporter" depends-on="partnershipPluginService" lazy-init="false">
<property name="registryPort" value="${rmi.port}"/>
<property name="serviceName" value="partnershipPluginService"/>
<property name="serviceInterface" value="com.otr.security.synchronization.service.PartnershipPluginService"/>
<property name="service" ref="partnershipPluginService"/>
</bean>
Both this beans declared as not lazy. I thibk, enough declare at least one RmiServiceExporter as non lazy to have the same behavior.
In this configuration there are one big disadvantage. It doesn't work. I have exception in context creation process
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'partnershipSystemPluginService' defined in
class path resource
[security/serverSecurityServices.xml]: Cannot
resolve reference to bean 'cryptoSettingsService' while setting bean
property 'cryptoSettingsService'; nested exception is
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'cryptoSettingsService': Bean with name
'cryptoSettingsService' has been injected into other beans
[jinnCryptoService,jinnCryptoServerService] in its raw version as part
of a circular reference, but has eventually been wrapped. This means
that said other beans do not use the final version of the bean. This
is often the result of over-eager type matching - consider using
'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for
example.
At first look, there is no circular dependency between jinnCryptoService and jinnCryptoServerService. If I make both RmiServiceExporter and partnershipPluginService lazy like others - context creates with no exceptions, but RMI doesn't work.
So, is any way to have context and RMI working? Thanks for helping me and wasting your time.
So,I found a solution.
I took a look for context's neighborhood and got a few contexts with beans like RmiServiceExporter. That contexts is not lazy and get started after lazy contexts with beans like partnershipPluginService.
I replaced RmiServiceExporter into new context and the problem is solved.
If you'll be in my place, please take a few looks on the problem from different angles and you find an answer.
Thanks to all, who read this post, trying to help me.
The Spring documentation provides the following example to show us the reason why we need to define aop:scoped-proxy explicitly in beans of scope session, reques, etc.
<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>
We need proxy here, because for each request to the userPreferences bean we want to delegate one to the actual session-scoped bean's instance. That's clear. But the documentation also said that this's a deafult behavior for singletone/prototype scoped beans.
Consider the following example:
<bean id="userPreferences" class="com.foo.UserPreferences" />
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
Why do we need in proxy in the case of singletone-scoped beans? Doesn't injecting and calling to proxy cause some performance overhead?
Question: For performance sakes, could we avoid injecting proxy and inject actual bean instances in the case of the singletone-scoped beans instead?
Suppose have following beach definition:
<bean id="singletonBean" class="...">
<property name="instanceBean" ref="instanceBean"/>
</bean>
<bean id="instanceBean" class="..." scope="prototype"/>
When I call:
singletonBean = context.getBean("singletonBean");
...some code...
singletonBean = context.getBean("singletonBean");
Would property instanceBean of singletonBean be initialized again or it would just use already created singleton?
Would just use already created singleton.
A prototyped inner bean of a singleton won't be recreated each time you get the singleton from context. The singleton and all is references are created one for all.
But context.getBean("instanceBean"); would give you a new since scope is 'prototype'.
instanceBean is set only once on startup, so you can get the instanceBean by singletonBean.getInstanceBean() if you like.
When invoked context.getBean("singletonBean") always it contains the same instance of instanceBean, though the scope is prototype in the bean definition.
On the contrary if the container bean is of scope prototype and it refers to a bean which is defined with scope singleton, always the inner bean would be singleton. Eg:-
<bean id="outer" class="OuterBean" scope="prototype">
<property name="innerBean" ref="inner" />
</bean>
<bean id="inner" class="InnerBean" scope="singleton"/>
OuterBean outer1 = (OuterBean) context.getBean("outer");
OuterBean outer2 = (OuterBean) context.getBean("outer");
Here both outer1 and outer2 will contain same instance of InnerBean.
In a multitheaded environment, if innerBean holds any shared data, it can lead to race condition.
<bean id="data.emf"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" >
<property name="persistenceUnitName" value="transactions-optional" />
</bean>
from what i know by default all bean are singleton (according to document) but i somehow still getting duplicated creating of entitymanagerfactory. is there any parameter i can set for bean above in spring 3.0 to force singleton? the problem only appear in gae production, on hosted mode, no problem
You can force a bean to be a singleton like this:
<bean scope="singleton" ... >
</bean>
You generally don't need to do this, however, since singleton is the default scope, and there's no way to change the default.
The Spring DEBUG-level logs will generate entries every time a bean is instantiated, so have a look through there to see when and where your bean is being processed.
Maybe the problem doesn't come form the scope. Are you sure you haven't defined another bean in anther place of the program (for example with an annotation) or in another context file? Comment that bean definition and try if it can find a instance of it without declaring it here.