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="...NonStaticBarInterfaceFactory"/> <bean id="bar" factory-bean="barFactory" factory-method="getInstance"/>
bar这个bean,中有factory-bean这个属性,就是告诉容器,bar=barFactory.getInstance();
如果barFactoy的getinstance也需要参数呢?
同样使用:<constructor-arg>
FactoryBean
上面写的工厂方法还有一个替代方法,就是FactoryBean
FactoryBean是Spring容器提供的一种可以扩展容器对象实例化逻辑的接口,请不要将其与容器名称BeanFactory相混淆。FactoryBean,其主语是Bean,定语为Factory,也就是说,它本身与其他注册到容器的对象一样,只是一个Bean而已,只不过,这种类型的Bean本身就是生产对象的工厂(Factory)。
我们先看看FactoryBean的签名。
public interface FactoryBean {
Object getObject() throws Exception;
Class getObjectType(); //如果不能确定返回的类型,getObjectType就返回null
boolean isSingleton();
}
完全能看懂,没有压力呀。
如果我们想每次得到的日期都是第二天,可以使用如下的代码
import org.joda.time.DateTime;
import org.springframework.beans.factory.FactoryBean;
public class NextDayDateFactoryBean implements FactoryBean {
public Object getObject() throws Exception {
return new DateTime().plusDays(1);
}
public Class getObjectType() {
return DateTime.class;
}
public boolean isSingleton() {
return false;
}
}
要使用NextDayDateFactoryBean,只需要如下这样将其注册到容器即可:
<bean id="nextDayDateDisplayer" class="...NextDayDateDisplayer"> <property name="dateOfNextDay"> <ref bean="nextDayDate"/> </property> </bean> <bean id="nextDayDate" class="...NextDayDateFactoryBean"> </bean>
从xml配置上似乎和以前没有什么差别,但是nextDayDateDisplayer里的属性dateOfNextDay并不是NextDayDateFactoryBean而是NextDayDateFactoryBean中getObject方法返回的对象。
public class NextDayDateDisplayer {
private DateTime dateOfNextDay;
// 相应的setter方法
// ...
}
如果一定要取得FactoryBean本身的话,可以通过在bean定义的id之前加前缀&来达到目的。
Object nextDayDate = container.getBean("nextDayDate");
assertTrue(nextDayDate instanceof DateTime);
Object factoryBean = container.getBean("&nextDayDate");
assertTrue(factoryBean instanceof FactoryBean);
assertTrue(factoryBean instanceof NextDayDateFactoryBean);
Object factoryValue = ((FactoryBean)factoryBean).getObject();
assertTrue(factoryValue instanceof DateTime);
assertNotSame(nextDayDate, factoryValue);
ssertEquals( ((DateTime)nextDayDate).getDayOfYear(),
((DateTime)factoryValue).getDayOfYear() );
感谢glt
Spring揭秘 读书笔记 三 bean的scope与FactoryBean的更多相关文章
- spring揭秘 读书笔记 六 bean的一生
我们知道,Spring容器具有对象的BeanDefinition来保存该对象实例化时需要的数据. 对象通过container.getBean()方法是才会初始化该对象. BeanFactory 我们知 ...
- spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定
本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...
- spring揭秘 读书笔记 一 IoC初探
本文是王福强所著<<spring揭秘>>一书的读书笔记 ioc的基本概念 一个例子 我们看下面这个类,getAndPersistNews方法干了四件事 1 通过newsList ...
- spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定
本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...
- Spring揭秘读书笔记 八 数据访问异常体系
这篇博客 来自spring揭秘一书的第十三章 为什么要有访问异常都有一个体系,这个我们得从DAO模式说起. DAO模式 任何一个系统,不管是一个最简单的小系统,还是大规模的系统,都得跟数据打交道,说白 ...
- Spring揭秘 读书笔记 四----方法注入
我们知道,拥有prototype类型scope的bean,在请求方每次向容器请求该类型对象的时候,容器都会返回一个全新的该对象实例. 我们看下面的例子: public class MockNewsPe ...
- Spring揭秘 读书笔记 七 BeanFactory的启动分析
首先,先看我自己画的BeanFactory启动时的时序图. 第一次接触时序图,可能有些地方画的不是很符合时序图的规则,大家只关注调用顺序即可. public static void main(Stri ...
- spring揭秘读书笔记----spring的ioc容器之BeanFactory
spring的ioc容器是一种特殊的Ioc Service Provider(ioc服务提供者),如果把普通的ioc容器认为是工厂模式(其实很相似),那spring的ioc容器只是让这个工厂的功能更强 ...
- Spring揭秘 读书笔记 五 容器的启动
Spring的IoC容器所起的作用,就是生产bean,并维持bean间的依赖关系.它会以某种方式加载Configuration Metadata(通常也就是XML格式的配置信息),然后根据这些信息绑定 ...
随机推荐
- 【mybatis深度历险系列】延迟加载
在前面的博文中,小编主要简单的介绍了mybatis中的高级映射,小伙伴们可以把mybatis和hibernate的因素进行对比,更加有利于理解.今天这篇博文,小编主要来简单介绍一下mybatis中的延 ...
- [OpenCV]在显示窗口中截图
[OpenCV]在显示窗口中截图 简介 介绍使用OpenCV实现简单的截图功能.首先阐述实现此功能的基本步骤,然后给出实现代码,最后贴出实验结果以及遇到的问题. 基本步骤 我们需要知道OpenCV使用 ...
- iOS升级HTTPS通过ATS你所要知道的
由于苹果规定2017年1月1日以后,所有APP都要使用HTTPS进行网络请求,否则无法上架,因此研究了一下在iOS中使用HTTPS请求的实现.网上搜索了一些比较有用资料,大家可以参考下 苹果强制升级的 ...
- 【完整的App项目】颖火虫笔记
这是本人花大概一个星期开发出来的一款App,这是一款类似印象笔记的App,随时记录您的生活点滴.首先说一下自己为何要开发这款App,因为自己手机系统自带的笔记应用功能太low,界面不够漂亮,所以自己就 ...
- 【Java二十周年】Delphi转行java的一些小感触
本文纯属一届小码农对java使用过程的体验感触 目录: 初遇java编程语言 与java的擦肩 深入java 跨平台性 开源支持 web的支撑 初遇java编程语言 刚上大学的时候,完全是个电脑盲.刚 ...
- Dynamics CRM2016 时间字段属性中的新增行为
之前的博客中有特地介绍过CRM中的时间字段以及它在不同的应用场景中涉及的时制转换,而CRM2016又给时间字段添加了新的行为,具体见下属截图,简单介绍下每个图中对应的行为的意思,最后会做demo来具体 ...
- SQLite 删除表(http://www.w3cschool.cc/sqlite/sqlite-drop-table.html)
SQLite 删除表 SQLite 的 DROP TABLE 语句用来删除表定义及其所有相关数据.索引.触发器.约束和该表的权限规范. 使用此命令时要特别注意,因为一旦一个表被删除,表中所有信息也将永 ...
- maven项目管理
systemPath方式 有些不通用的包,maven仓库没有,只能通过本地包依赖,就像下面方式: 在需要依赖的项目建lib文件夹,如下: 然后在pom.xml项目管理文件里面加入本地依赖,如下 这种情 ...
- FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)
===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...
- 带你深入理解STL之List容器
上一篇博客中介绍的vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,很好的支持了随机存取,但由于是连续空间,所以在中间进行插入.删除等操作时都造成了内存块的拷贝和移动,另外在内存空间 ...