|
From: Trevor B. <tre...@gm...> - 2005-09-26 23:33:26
|
Hi all,
I wanted to draw attention to a behavior in Spring that I was
already aware of, but which bit me unexpectedly in a project I was
called in to help. (it cropped up due to some 'mis-use' of Spring).
I found this with Spring 1.2.3. When I went back to Spring 1.0.2 I
found that it exhibited different behavior, which I consider more
correct. I found the JIRA issue that relates to this change:
http://opensource2.atlassian.com/projects/spring/browse/SPR-174
Let me explain the scenario I encountered.
Spring can call private constructors for beans (since 1.1RC1). Take
this simple Java class:
public class MySingletonBean {
private static MySingletonBean s_instance =3D new MySingletonBean();
private MySingletonBean() {
System.out.println("Creating MySingletonBean");
}
public static MySingletonBean getInstance() {
return s_instance;
}
}
With a spring bean definition like so:
<bean id=3D"MyBean"
class=3D"com.example.MySingletonBean">
</bean>
I find that when I load an ApplicationContext, Spring successfully
calls the private constructor (by calling setAccessible(true) on the
java.lang.Constructor object).
When I think about it, I guess that I would have expected that Spring
would have flagged this usage as an error or at least a warning - e.g.
"No public constructor in class [class com.example.MySingletonBean]".
I came across this feature when I was called in to help out an
application that was having a problem which turned out to be multiple
singletons within a single classloader. A class was defined as a
singleton using the typical pattern (i.e. private constructor, static
getInstance() method), but was also defined in a Spring context using
a bean definiton like so:
<bean id=3D"MyBean"
class=3D"com.example.MySingletonBean">
</bean>
Of course to be correct, the bean definition should have been:
<bean id=3D"MyBean"
class=3D"com.example.MySingletonBean"
factory-method=3D"getInstance">
</bean>
Different places in the application code were accessing the same
object in different ways - some were using Spring, others were calling
getInstance(). Of course, we had two instances of the singleton within
the application - so the code was not behaving correctly.
While the design of this part of the app was not exactly correct/good
practice (should really just be using one mechanism to access the
object) - it still exposed a behavior in Spring that I think may not
be wholly intuitive. I have since reworked this to something I think
is more suitable, removing the singleton pattern implementation and
simply using Spring to wire up the singleton object to all objects
that need it.
With Spring 1.0.2 - we do not have this problem. Spring throws an error:
Exception in thread "main"
org.springframework.beans.factory.BeanDefinitionStoreException: Error
registering bean with name 'MyBean' defined in class path resource
[applicationContext.xml]: Validation of bean definition with name
failed; nested exception is
org.springframework.beans.factory.support.BeanDefinitionValidationException=
:
No public constructor in class [class com.example.MySingletonBean]
I was just curious as to the development team's thoughts on this
issue. I understand there are scenarios where we may want to
instantiate beans that only have private constructors. But it does
open up the possibility for miss-use - as can be seen from my concrete
example above.
Regards,
Trevor
|