昨天晚上看spring In Action这本书,说spring会调用默认的构造函数来生成bean实例,如果该默认的构造函数为私有的时候,我们可以指定factory-method来生成实例。我试了一下,下面是代码
- Java code
public class SubBean { private static SubBean instance = null; private SubBean() { System.out.println("this is private constructor"); } public static synchronized SubBean getInstance() { if (instance == null) { instance = new SubBean(); } return instance; }}
在配置文件中这么定义的bean,bean定义为prototype类型的
- XML code
<bean id="subBean" class="test.SubBean" scope="prototype"></bean>
这个事测试类
- Java code
public class Test { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "D:/workspace/flex/opview/src/main/java/test/application.xml"); SubBean bean = (SubBean) context.getBean("subBean"); SubBean bean1 = (SubBean) context.getBean("subBean"); System.out.println(bean == bean1); }}
subBean是一个单例,但是打印出来的结果是
this is private constructor
this is private constructor
this is private constructor
false
false说明bean和bean1不是指向同一个对象的,而且私有的构造方法也被调用了
如果xml文件中给bean加一个factory-method="getInstance"属性,那么打印出来的结果就是true
------解决方案--------------------
是作用域的问题
singleton 在spring IOC容器中仅存在一个Bean实例,Bean以单实例的方式存在.
prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new XxxBean()的操作.
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于webApplicationContext环境.
session 同一个HTTP session共享一个Bean,不同HTTP session使用不同的Bean,该作用域仅适用于webApplicationContext环境.
globalSession 同一个全局session共享一个Bean,一般用于portlet应用环境,该作用域仅适用于webApplicationContext环境.
------解决方案--------------------
Spring是利用反射去初始化化类的。私有的属性反射也是可以访问到的,类似:
//get Constructor
Class clazz = Class.forName("T");
Constructor cons = clazz.getDeclaredConstructor(null);
//set accessble to access private constructor
cons.setAccessible(true);
cons.newInstance(null);
只不过不建议你这么利用Spring而已。
因为既然你指定了构造函数为私有,说明你设计上有特殊考虑,不希望构造函数被直接调用,比如要准备某些静态资源、共享环境或其它事情,所以希望用工厂模式来做。然后你又借助Spring来绕开这些保护机制,那不是很容易搬起石头砸自己脚么?