Spring揭秘 读书笔记 三 bean的scope与FactoryBean
本书可作为王富强所著<<Spring揭秘>>一书的读书笔记
第四章 BeanFactory的xml之旅
bean的scope
scope有时被翻译为"作用域",scope用来声明容器中的对象所应该处的限定场景或者说该对象的存活时间,即容器在对象进入其对应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后。容器一般会销毁这些对象。scope共同拥有5个,singleton,prototype,request,session,global session
前两个是通用的,中间三个仅仅是在web系统中才才用到,最后一个global session仅仅有应用在基于portlet的Web应用程序中才有意义,它映射到portlet的global范围的session。
我们能够通过使用<bean>的singleton或者scope属性来指定对应对象的scope,当中,scope属性仅仅能在 SD格式的文档声明中使用,类似于例如以下代码所演示的形式:
DTD:
<bean id="mockObject1" class="...MockBusinessObject" singleton="false"/>
XSD:
<bean id="mockObject2" class="...MockBusinessObject" scope="prototype"/>
singleton
singleton:容器中仅仅有一个对象,谁要都是这个一个。仅仅有容器不销毁或者退出,她就一直存在。
配置情况,由于scope默认的就是singleton,以下三种方式效果一样。
<!-- DTD or XSD -->
<bean id="mockObject1" class="...MockBusinessObject"/>
<!-- DTD -->
<bean id="mockObject1" class="...MockBusinessObject" singleton="true"/>
<!-- XSD -->
< bean id="mockObject1" class="...MockBusinessObject" scope="singleton"/>
prototype
prototype:每次请求都是一个新的对象。并且,一旦这个新的对象给了请求方,那么容器就不在持有对这个对象的引用。就像嫁出去的姑娘,泼出去的水,娘家以后无论了。
配置方式:
<!-- DTD -->
<bean id="mockObject1" class="...MockBusinessObject" singleton="false"/>
<!-- XSD -->
<bean id="mockObject1" class="...MockBusinessObject" scope="prototype"/>
request
request:和prototype没什么差别,在web情况下每来一个请求,分配一个实例。
配置方式
<bean id="requestProcessor" class="...RequestProcessor" scope="request"/>
session
session:对于放到session中的信息,能够将scope设置为session,它除了比request更长的存活时间外,其它方面没什么差别。
配置方式:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
工厂方法与FactoryBean
我们看以下的代码:
public class Foo { private BarInterface barInstance; public Foo() { // 我们应该避免这样做 // instance = new BarInterfaceImpl(); } // ... }
为什么要避免这么做?
由于接口与实现类之间有了耦合。
有了耦合咋了,为什么就不能有耦合。
假设我不想用BarInterfaceImpl,先换成Bar2InterfaceImpl。
上面的方法就是得改Foo类的编码,假设n个类中都有instance = new BarInterfaceImpl(); 那么我岂不是得要改n处。
还有一方面,假设实现类(比如barInstance)是来自外部jar包的,你没办法把它纳入spring的管理范围,哪有怎样?
为之奈何?
工厂方法
public class Foo { private BarInterface barInterface; public Foo() { // barInterface = BarInterfaceFactory.getInstance(); // 或者 // barInterface = new BarInterfaceFactory().getInstance(); } ... }
这样一来,Foo直接依赖于BarInterfaceFactory。假设产品有了变化,我仅仅用改工厂,而不用"告诉"每个使用者产品改变了。
静态工厂方式
public class StaticBarInterfaceFactory { public static BarInterface getInstance() { return new BarInterfaceImpl(); } }
Foo中的BarInterface有相应的get/set方法。
要想通过静态工厂把BarInterfaceImpl注入到Foo中,我们能够这样
xml例如以下:
<bean id="foo" class="...Foo"> <property name="barInterface"> <ref bean="bar"/> </property> </bean> <bean id="bar" class="...StaticBarInterfaceFactory" factory-method="getInstance"/>
bean中有了factory-method,就说明这个类并非使用默认的构造方法产生的,而是使用getInstance方法。再换句话说,bar这个bean最后的返回不是StaticBarInterfaceFactory,而是getInstance这种方法的返回值。
假设getInstacne须要參数呢?比如:
public class StaticBarInterfaceFactory { public static BarInterface getInstance(Foobar foobar) { return new BarInterfaceImpl(foobar); } }xml例如以下:
<bean id="foo" class="...Foo"> <property name="barInterface"> <ref bean="bar"/> </property> </bean> <bean id="bar" class="...StaticBarInterfaceFactory" factory-method="getInstance"> <constructor-arg> <ref bean="foobar"/> </constructor-arg> </bean> <bean id="foobar" class="...FooBar"/>
仅仅有bar中的constructor-arg下的參数是给getInstance用的,而不是StaticBarInterfaceFactory。
(还有一方面,静态工厂也没有显示的构造方法呀)
非静态工厂方式
public class NonStaticBarInterfaceFactory { public BarInterface getInstance() { return new BarInterfaceImpl(); } ... }
由于工厂方法为非静态的,我们仅仅能通过某个NonStaticBarInterfaceFactory实例来调用该方法(哦,错了。是容器来调用),那么也就有了例如以下的配置内容:
<bean id="foo" class="...Foo"> <property name="barInterface"> <ref bean="bar"/> </property> </bean> <bean id="barFactory" class=&q