View Full Version : Problem with ProxyFactoryBean creating non singleton beans.
ram_2000
Aug 15th, 2004, 05:28 PM
I using 1.1 RC1
I have a simple bean definition like below:
<beans>
<bean id="businesslogicbean"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>aop_simple.IBusinessLogic</value>
</property>
<property name="target">
<ref local="beanTargetPrototype"/>
</property>
<property name="singleton"><value>false</value>
</property>
</bean>
<bean id="beanTargetPrototype" singleton="false"
class="aop_simple.BusinessLogic"/>
</beans>
I have a simple tester class that invokes a method on the interface..
public static void main(String [] args)
{
// Read the configuration file
ApplicationContext ctx = new FileSystemXmlApplicationContext("aop_simple/springconfig.xml");
//Instantiate an object
IBusinessLogic testObject = (IBusinessLogic) ctx.getBean("businesslogicbean");
testObject.foo();
}
The above code works fine if i use singletons. But i get the following exception when i set "singleton" to false.
I get the following exception:
org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'businesslogicbean': FactoryBean threw exception on object creation; nested exception is org.springframework.aop.framework.AopConfigExcepti on: Target name cannot be null when refreshing!
org.springframework.aop.framework.AopConfigExcepti on: Target name cannot be null when refreshing!
at org.springframework.aop.framework.ProxyFactoryBean .refreshTarget(ProxyFactoryBean.java:392)
at org.springframework.aop.framework.ProxyFactoryBean .newPrototypeInstance(ProxyFactoryBean.java:223)
at org.springframework.aop.framework.ProxyFactoryBean .getObject(ProxyFactoryBean.java:200)
at org.springframework.beans.factory.support.Abstract BeanFactory.getObjectForSharedInstance(AbstractBea nFactory.java:517)
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:159)
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:136)
at org.springframework.context.support.AbstractApplic ationContext.getBean(AbstractApplicationContext.ja va:426)
at aop_simple.ProxyNonSingleton.main(ProxyNonSingleto n.java:15)
Exception in thread "main"
Looks like "targetName" field in ProxyFactoryBean is null and the refreshTarget() method is failing.....But don't know why? Am i doing something wrong in the config?
Thanks,
Ram.
Colin Sampaleanu
Aug 15th, 2004, 05:52 PM
Ram,
Don't forget that ProxyFactoryBean, like any FactoryBean, is itself a singleton, and any properties you set on it get set only once. Now of course it can generate a singleton or prototype proxy, as a result of the getBean call.
So the problem is that you are trying to create a prototype proxy, which also by definition means a prototype target is needed, but you are feeding in the target in a non-prototype fashion via the target property). You need to feed it the target by name, as the targetName property, so it can create a new proxy around a new prototype target instance.
I'll check if the manual explains this well enough, but hopefully the above is clear.
Regards,
ram_2000
Aug 15th, 2004, 06:56 PM
Thanks for your quick reply Colin.
RE: >>>> "So the problem is that you are trying to create a prototype proxy, which also by definition means a prototype target is needed, but you are feeding in the target in a non-prototype fashion via the target property). You need to feed it the target by name, as the targetName property, so it can create a new proxy around a new prototype target instance. "
I understand why it cannot be a "ref" and it should be same as "interceptorNames". But the targetName property is not exposed in the ProxyFactoryBean (its private).
It would be nice if the definitions were consistent (always use target name for the proxy...and based on the target bean definition a prototype or singleton proxy will be returned....much like the "interceptorNames"...). This way we can avoid the "singleton" property for the proxy itself.
RE: >>>> I'll check if the manual explains this well enough, but hopefully the above is clear.
The manual does not talk about targetName property.
Thanks again for your attention,
Ram.
ram_2000
Aug 15th, 2004, 08:23 PM
I got this to work using "targetSource" and using "org.springframework.aop.target.PrototypeTargetSour ce" implementation class.
Two levels of indirection for something very simple.
<beans>
<bean id="businesslogicbean"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>aop_simple.IBusinessLogic</value>
</property>
<property name="targetSource"><ref local="targetSource"/>
</property>
</bean>
<bean id="targetSource"
class="org.springframework.aop.target.PrototypeTargetSour ce">
<property name="targetBeanName">
<value>beanTargetPrototype</value>
</property>
</bean>
<bean id="beanTargetPrototype" singleton="false"
class="aop_simple.BusinessLogic"/>
</beans>
It would be nice if i specified "target" as bean name/id for the ProxyFactoryBean and spring figured out based on bean definition if it should use prototype or singleton. This way, I can use the target source only for special cases (HotSwappable, Poolable etc..). Both "target" and "targetSource" should not be specified together...and also the "singleton" attribute won't be necessary (in the above bean definition setting "singleton" property to true for the ProxyFactoryBean still returned prototype objects...).
Also, the current HotSwappableTargetSource impl can work only with singletons (as the constructor arg takes only an object reference). Again, it would be nice if the HotSwappableTagetSource just took the targetBeanName and figured out based on bean definition if its a prototype or singleton (instead of creating two class HotSwappableSingletonTargetSource and HotSwappablePrototypeTargetSource ).
It will help if the manual is updated with when to use bean "ref" vs name.
Thoughts?
Colin Sampaleanu
Aug 15th, 2004, 10:48 PM
Sorry about overlooking the fact that TargetName is private. However, as the JavaDocs for the class do mention pretty specifically right at the beginning, you can just use the target bean name as the last name in the interceptorNames property. If if is not an Interceptor or Advisor, it is considered to be the target, and a SingletonTargetSource is created to wrap it, which is then set as the targetSource.
So it's actually very simple...
This JavaDoc is probably adequate for the most part, although I'll mention this usage in terms of prototypes a bit more explicitly. Ditto for the manual, where prototypes are described not even to this level.
Regards,
wstrange
Aug 30th, 2004, 03:14 PM
I also have a need to wrap a prototype bean using the TransactionFactoryProxyFactoryBean.
I did manage to grind this out using the technique that Ram suggested (using the ProxyFactoryBean, PrototypeTargetSource, etc.), but I was hoping there was an easier way!
Wouldn't it be safe for Spring to assume that if the target source was a prototype - that it needs to be wrapped it in a PrototypeTargetSource?
Warren
Colin Sampaleanu
Aug 31st, 2004, 12:01 PM
Warren,
Just set it as the last interceptor name, as per my previous post.
wstrange
Aug 31st, 2004, 01:22 PM
if is not an Interceptor or Advisor, it is considered to be the target, and a SingletonTargetSource is created to wrap it, which is then set as the targetSource.
But if my target is a prototype - this wont work, right? I need to wrap it in a PrototypeTargetSource, and then set the targetSource property of my ProxyBeanFactory.
I would be nice to avoid all the extra config code to wrap my targets in a PrototypeTargetSource
Warren
Colin Sampaleanu
Aug 31st, 2004, 01:25 PM
That _will_ work. This whole thread was about prototypes...
wstrange
Aug 31st, 2004, 05:32 PM
I hate to be dense about this, but....
I have a test that gets two proxy instances from the factory.
If I set the last interceptor to be the name of my prototype target, the log files indicate that the same instance of the target is returned for newly created proxies (i.e. - each proxy points at a single instance of my target bean - not a newly created prototype).
If instead, I use the <targetSource> property, and I wrap my targets in a PrototypeTargetSource, the log messages change to "about to invoke blah..blah on object of class Foobar....". Which to me looks like it is doing the right thing (i.e. creating a new instance of my target, every time the proxy factory creates a new bean)
Am I missing something here?
Colin Sampaleanu
Aug 31st, 2004, 06:33 PM
Are you sure the 'singleton' JavaBean property of the ProxyFactory bean is set to false? If it's not, then indeed you will get back the same instance.
If you set the 'singleton' xml attribute of the target bean itself to false, and then on the proxy itself set the singleton _property_ like this, then what it will do on the getObject call is go through a sequene where it refreshes the advisor chain, and gets a new target by name.
You should be able to see stuff in the log which shows this, such as:
"Creating copy of prototype ProxyFactoryBean config: xxxx"
wstrange
Sep 1st, 2004, 11:38 AM
Are you sure the 'singleton' JavaBean property of the ProxyFactory bean is set to false? If it's not, then indeed you will get back the same instance.
Ahh.... now I get it. Thanks for hitting me with a clue stick :-)
I got confused between setting the singleton attribute on the proxy factory bean itself ( singleton="true"), which of course is not allowed, vs. settting the singleton property that controls how the proxy creates new instances.
This is all rather obvious now - but it is somewhat confusing the first time you see it. It all works fine now - many thanks for the help!
jfinley
Jan 22nd, 2008, 02:51 PM
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<!--
To get the *prototype* behavior to work:
On the proxy factory that you are wiring....
-Do not use a target property as the examples in most places
lead you. That only works for singletons for some reason
-put the target bean that you want an instance of as the last
bean name in the interceptorNames property. Yea, that's
intuitive.
-Add the property of singleton and a value of false to the
factory. That actually makes sense.
On the target bean
-add the singleton attribute set to false
That should help you get it together
-->
<beans>
<bean id="accountsFactory"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>aop.explore.Accounts</value>
</property>
<property name="interceptorNames">
<list>
<value>theTracingBeforeAdvisor</value>
<value>beanTarget</value>
</list>
</property>
<property name="singleton">
<value>false</value>
</property>
</bean>
<bean id="beanTarget" class="aop.explore.AccountsImpl" singleton="false"></bean>
<!--Advisor pointcut definition for before advice -->
<bean id="theTracingBeforeAdvisor"
class="org.springframework.aop.support.RegexpMethodPointc utAdvisor">
<property name="advice">
<ref local="theTracingBeforeAdvice"/>
</property>
<property name="pattern">
<value>.*</value>
</property>
</bean>
<!--Advisor pointcut definition for after advice -->
<bean id="theTracingAfterAdvisor"
class="org.springframework.aop.support.RegexpMethodPointc utAdvisor">
<property name="advice">
<ref local="theTracingAfterAdvice"/>
</property>
<property name="pattern">
<value>.*</value>
</property>
</bean>
<!--Advisor pointcut definition for exception logging advice -->
<bean id="theLogTracingAdvisor"
class="org.springframework.aop.support.RegexpMethodPointc utAdvisor">
<property name="advice">
<ref local="theLogTracingAdvice"/>
</property>
<property name="pattern">
<value>.*</value>
</property>
</bean>
<!-- Advice classes -->
<bean id="theTracingBeforeAdvice"
class="aop.explore.AccountDataInterceptor"/>
<bean id="theTracingAfterAdvice"
class="aop.explore.TracingAfterAdvice"/>
<bean id="theLogTracingAdvice"
class="aop.explore.LoggingThrowsAdvice"/>
</beans>
vBulletin® v3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd.