我们知道,拥有prototype类型scope的bean,在请求方每次向容器请求该类型对象的时候,容器都会返回一个全新的该对象实例。

我们看下面的例子:

public class MockNewsPersister implements IFXNewsPersister {
  private FXNewsBean newsBean; 

  public void persistNews(FXNewsBean bean) {
   persistNewes();
   }
  public void persistNews() {
   System.out.println("persist bean:"+getNewsBean());
  }
  public FXNewsBean getNewsBean() {
   return newsBean;
   } 

  public void setNewsBean(FXNewsBean newsBean) {
   this.newsBean = newsBean;
  }
} 

相应的xml为:

<bean id="newsBean" class="..domain.FXNewsBean" singleton="false">
</bean>
<bean id="mockPersister" class="..impl.MockNewsPersister">
  <property name="newsBean">
   <ref bean="newsBean"/>
  </property>
</bean>  

我们看测试代码

BeanFactory container = new XmlBeanFactory(new ClassPathResource(".."));
MockNewsPersister persister = (MockNewsPersister)container.getBean("mockPersister");
persister.persistNews();
persister.persistNews(); 

输出: 

persist bean:..domain.FXNewsBean@1662dc8 

persist bean:..domain.FXNewsBean@1662dc8 

为什么两次persister.persistNews(); 打印的内容一样?

那么凭什么为什么两次persister.persistNews(); 打印的内容要一样?

不是说请求singleton="false"的对象时每次返回的都是不一样的么?

请求singleton="false"的对象时每次返回的对象是不一样的,这句话没错,但是在上面的情况中,MockNewsPersister请求了几次newsBean呢?

请求了一次。

换句话说,FXNewsBean的构造方法只执行了一次。



那我怎么在一个singleton的对象里,动态地获得prototype型的bean呢(就是每次获得的bean都不一样)?********

至少有三个答案

使用方法注入

xml如下

<bean id="newsBean" class="..domain.FXNewsBean" singleton="false">
</bean>
<bean id="mockPersister" class="..impl.MockNewsPersister">
  <lookup-method name="getNewsBean" bean="newsBean"/>
</bean>  

lookup-method的意思就是:spring通过cglib技术,为MockNewsPersister生成一个子类,并复写其getNewBean方法。

之后每次调用mockPersister的getNewsBean方法都动态的返回一个newsBean实例。

当然MockNewsPersister的getNewsBean必须满足下面的形式

<public|protected> [abstract] <return-type> theMethodName(no-arguments); 

换句话说,就是getNewsBean必须能被复写。



其实我们大可以直接在persister.persistNews()里new一个FXNewsBean,而不用非得从容器里获得。这里引这个例子,只是为了说明方法注入。

使用BeanFactoryAware接口

其实即使没有方法注入,在上面的例子中,在getNewsBean中,只要我们调用BeanFactory.getBean("newsBean")也能动态的获得newsbean。

问题是,如果在一个普通的bean中获得BeanFactory的引用?

Spring框架提供了一个BeanFactoryAware接口,容器在实例化实现了该接口的bean定义的过程中,会自动将容器本身注入该bean。这样,该bean就持有了它所处的BeanFactory的引用。

BeanFactoryAware的定义如下代码所示:

public interface BeanFactoryAware {
  void setBeanFactory(BeanFactory beanFactory) throws BeansException;
  } 

实现BeanFactoryAware接口的情况:

public class MockNewsPersister implements IFXNewsPersister,BeanFactoryAware {
  private BeanFactory beanFactory; //  待注入的beanFactory

  public void setBeanFactory(BeanFactory bf) throws BeansException {
   this.beanFactory = bf;
  }
  public void persistNews(FXNewsBean bean) {
	persistNews();
  }
  public void persistNews() 1  {
   System.out.println("persist bean:"+getNewsBean());
  }
  public FXNewsBean getNewsBean() {
  return beanFactory.getBean("newsBean");   //使用beanFactory
  }
} 

xml简化为

<bean id="newsBean" class="..domain.FXNewsBean" singleton="false">
</bean>
<bean id="mockPersister" class="..impl.MockNewsPersister">
</bean>  

如此,可以预见到,输出的结果将与我们所预期的相同:   

persist bean:..domain.FXNewsBean@121cc40 

persist bean:..domain.FXNewsBean@1e893df  

实际上,方法注入动态生成的子类,完成的是与以上类似的逻辑,只不过实现细节上不同而已。

使用ObjectFactoryCreatingFactoryBean

我们先看实现,再讲原理
将MockNewsPersister改成如下的样子
public class MockNewsPersister implements IFXNewsPersister {
  private ObjectFactory newsBeanFactory;  //就是ObjectFactoryCreatingFactoryBean

  public void persistNews(FXNewsBean bean) {
   persistNews();
  }
  public void persistNews()
  {
   System.out.println("persist bean:"+getNewsBean());
  }
  public FXNewsBean getNewsBean() {
   return newsBeanFactory.getObject();
  }
  public void setNewsBeanFactory(ObjectFactory newsBeanFactory) {
   this.newsBeanFactory = newsBeanFactory;
  }
}  

xml配置

<bean id="newsBean" class="..domain.FXNewsBean" singleton="false">
</bean>
<bean id="newsBeanFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
  <property name="targetBeanName">
   <idref bean="newsBean"/>
  </property>
</bean>
<bean id="mockPersister" class="..impl.MockNewsPersister">
   <property name="newsBeanFactory">
   <ref bean="newsBeanFactory"/>
  </property>
</bean> 

上面的<idref bean="newsBean"/> 

ref是获取这个bean的实例。用来实现注入功能。

假如只是想获取bean的名称 采用idref

使用idref标记允许容器在部署时,验证所被引用的bean是否存在。

等效于:

<bean id="newsBeanFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
    <property name="targetBeanName" value="newsBeanFactory" />
</bean> 

ObjectFactoryCreatingFactoryBean是 Spring 提供的一个 FactoryBean实现,它返回一个ObjectFactory实例。从ObjectFactoryCreatingFactoryBean返回的这个ObjectFactory实例可以为我们返回容器管理的相关对象。实际上,ObjectFactoryCreatingFactoryBean实现了BeanFactoryAware接口,它返回的ObjectFactory实例只是特定于与Spring容器进行交互的一个实现而已。使用它的好处就是,隔离了客户端对象对BeanFactory的直接引用

由于ObjectFactoryCreatingFactoryBean实现了BeanFactoryAware接口,所以ObjectFactoryCreatingFactoryBean里面也持有当前beanFactory的引用。

newsBeanFactory.getObject(),其实就是ObjectFactoryCreatingFactoryBean的getObject。

而ObjectFactoryCreatingFactoryBean内并没有getObject,要去它的父类AbstractFactoryBean找:

         //AbstractFactoryBean.java
	//singleton是个boolean型 默认是ture
	/**
	 * Expose the singleton instance or create a new prototype instance.
	 * @see 。createInstance()
	 * @see 。getEarlySingletonInterfaces()
	 */
	@Override
	public final T getObject() throws Exception {
		if (isSingleton()) {
			return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
		}
		else {
			return createInstance();
		}
	}

	//afterPropertiesSet会在容器启动时被调用
	/**
	 * Eagerly create the singleton instance, if necessary.
	 */
	public void afterPropertiesSet() throws Exception {
		if (isSingleton()) {
			this.initialized = true;
			this.singletonInstance = createInstance();
			this.earlySingletonInstance = null;
		}
	}
	//看到了吧 模板方法 具体的实现 要去子类里看 子类是谁呢?
	//是ObjectFactoryCreatingFactoryBean
	/**
	 * Template method that subclasses must override to construct
	 * the object returned by this factory.
	 * <p>Invoked on initialization of this FactoryBean in case of
	 * a singleton; else, on each {@link 。getObject()} call.
	 * @return the object returned by this factory
	 * @throws Exception if an exception occured during object creation
	 * @see 。getObject()
	 */
	protected abstract T createInstance() throws Exception;

不知道大家是否看懂了里面的实现过程

1 容器启动时就调用了AbstractFactoryBean的afterPropertiesSet方法。

2 afterPropertiesSet里

                        initialized = true;

this.singletonInstance = createInstance();

   这个createInstance其实是在子类ObjectFactoryCreatingFactoryBean里实现的。

3 ObjectFactoryCreatingFactoryBean的createInstance方法返回了一个TargetBeanObjectFactory,这TargetBeanObjectFactory能从spring容器里按照targetBeanName获得bean。

感谢glt

参考资料

http://blog.csdn.net/caihaijiang/article/details/5903227

Spring揭秘 读书笔记 四----方法注入的更多相关文章

  1. Spring揭秘 读书笔记 三 bean的scope与FactoryBean

    本书可作为王富强所著<<Spring揭秘>>一书的读书笔记  第四章 BeanFactory的xml之旅 bean的scope scope有时被翻译为"作用域&quo ...

  2. spring揭秘 读书笔记 一 IoC初探

    本文是王福强所著<<spring揭秘>>一书的读书笔记 ioc的基本概念 一个例子 我们看下面这个类,getAndPersistNews方法干了四件事 1 通过newsList ...

  3. spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...

  4. spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...

  5. Spring揭秘读书笔记 八 数据访问异常体系

    这篇博客 来自spring揭秘一书的第十三章 为什么要有访问异常都有一个体系,这个我们得从DAO模式说起. DAO模式 任何一个系统,不管是一个最简单的小系统,还是大规模的系统,都得跟数据打交道,说白 ...

  6. spring揭秘 读书笔记 六 bean的一生

    我们知道,Spring容器具有对象的BeanDefinition来保存该对象实例化时需要的数据. 对象通过container.getBean()方法是才会初始化该对象. BeanFactory 我们知 ...

  7. spring揭秘读书笔记----spring的ioc容器之BeanFactory

    spring的ioc容器是一种特殊的Ioc Service Provider(ioc服务提供者),如果把普通的ioc容器认为是工厂模式(其实很相似),那spring的ioc容器只是让这个工厂的功能更强 ...

  8. spring揭秘读书笔记----ioc的基本概念

    在看ico概念之前,先想一下我们平常需要依赖某个类时会怎么做? 无非是在要用到的地方写如下代码: Person person = new Person(); //然后就可以用person对象来获取Pe ...

  9. Spring.Net学习笔记(6)-方法注入

    一.开发环境 系统:win10 编译器:VS2013 二.涉及程序集 Spring.Core.dll 1.3.1 Common.Logging.dll 三.开发过程 1.项目结构 2.编写Mobile ...

随机推荐

  1. OpenResty 操作cookies

    在or中简单的使用cookies 复杂的操作请使用 [lua_resty_cookies](https://github.com/cloudflare/lua-resty-cookie) 基本操作 获 ...

  2. 使用Spring Boot开发Web项目(二)之添加HTTPS支持

    上篇博客使用Spring Boot开发Web项目我们简单介绍了使用如何使用Spring Boot创建一个使用了Thymeleaf模板引擎的Web项目,当然这还远远不够.今天我们再来看看如何给我们的We ...

  3. 短文本分析----基于python的TF-IDF特征词标签自动化提取

    绪论 最近做课题,需要分析短文本的标签,在短时间内学习了自然语言处理,社会标签推荐等非常时髦的技术.我们的需求非常类似于从大量短文本中获取关键词(融合社会标签和时间属性)进行用户画像.这一切的基础就是 ...

  4. Programming In Scala笔记-第八章、函数与闭包

    当程序的代码量增大时,就需要对各功能模块进行分割,这些分割的小模块就是本文中接下来会进行分析的函数.接下来的部分会讲解包括函数嵌套,函数字面量,以及函数值等概念. 一.方法 一会函数一会方法的,是不是 ...

  5. Android的Spinner控件用法解析

    微调框 微调框提供一种方法,让用户可以从值集中快速选择一个值.默认状态下,微调框显示其当前所选的值. 触摸微调框可显示下拉菜单,其中列有所有其他可用值,用户可从中选择一个新值. 您可以使用 Spinn ...

  6. Angular2入坑指南

    序 对后端开发来说,前端是神秘的,眼花缭乱的技术,繁多的框架,出名的不出名的好几百种,看是"繁荣",其实显得杂乱无章,但是我们在做开发的时候,技术选型还是主流的那么几个:浅析ang ...

  7. 有一台机器,上面有m个储存空间。然后有n个请求,第i个请求计算时需要占 R[i]个空间,储存计算结果则需要占据O[i]个空间(据O[i]个空间(其中O[i]<R[i])。问怎么安排这n个请求的顺序,使

    有一台机器,上面有m个储存空间.然后有n个请求,第i个请求计算时需要占 R[i]个空间,储存计算结果则需要占据O[i]个空间(据O[i]个空间(其中O[i]<R[i]).问怎么安排这n个请求的顺 ...

  8. Linux动态频率调节系统CPUFreq之二:核心(core)架构与API

    上一节中,我们大致地讲解了一下CPUFreq在用户空间的sysfs接口和它的几个重要的数据结构,同时也提到,CPUFreq子系统把一些公共的代码逻辑组织在一起,构成了CPUFreq的核心部分,这些公共 ...

  9. EBS销售订单挑库发放处理程序

    来自:http://blog.csdn.net/cunxiyuan108/article/details/6014769 在EBS实施中,经常遇到从外部传进来一个被登记的销售订单,需要通过程序进行销售 ...

  10. 1CCTableView的使用,TableView响应和小格子tableView实现

    1        CCTableView的使用 T26TableView.h #ifndef __T26TableView_H__ #define __T26TableView_H__ #includ ...