Spring揭秘 读书笔记 四----方法注入
我们知道,拥有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
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揭秘 读书笔记 四----方法注入的更多相关文章
- Spring揭秘 读书笔记 三 bean的scope与FactoryBean
本书可作为王富强所著<<Spring揭秘>>一书的读书笔记 第四章 BeanFactory的xml之旅 bean的scope scope有时被翻译为"作用域&quo ...
- spring揭秘 读书笔记 一 IoC初探
本文是王福强所著<<spring揭秘>>一书的读书笔记 ioc的基本概念 一个例子 我们看下面这个类,getAndPersistNews方法干了四件事 1 通过newsList ...
- spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定
本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...
- spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定
本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...
- Spring揭秘读书笔记 八 数据访问异常体系
这篇博客 来自spring揭秘一书的第十三章 为什么要有访问异常都有一个体系,这个我们得从DAO模式说起. DAO模式 任何一个系统,不管是一个最简单的小系统,还是大规模的系统,都得跟数据打交道,说白 ...
- spring揭秘 读书笔记 六 bean的一生
我们知道,Spring容器具有对象的BeanDefinition来保存该对象实例化时需要的数据. 对象通过container.getBean()方法是才会初始化该对象. BeanFactory 我们知 ...
- spring揭秘读书笔记----spring的ioc容器之BeanFactory
spring的ioc容器是一种特殊的Ioc Service Provider(ioc服务提供者),如果把普通的ioc容器认为是工厂模式(其实很相似),那spring的ioc容器只是让这个工厂的功能更强 ...
- spring揭秘读书笔记----ioc的基本概念
在看ico概念之前,先想一下我们平常需要依赖某个类时会怎么做? 无非是在要用到的地方写如下代码: Person person = new Person(); //然后就可以用person对象来获取Pe ...
- Spring.Net学习笔记(6)-方法注入
一.开发环境 系统:win10 编译器:VS2013 二.涉及程序集 Spring.Core.dll 1.3.1 Common.Logging.dll 三.开发过程 1.项目结构 2.编写Mobile ...
随机推荐
- PHP If...Else 语句
PHP If...Else 语句 条件语句用于根据不同条件执行不同动作. PHP 条件语句 当您编写代码时,您常常需要为不同的判断执行不同的动作.您可以在代码中使用条件语句来完成此任务. 在 PHP ...
- 手势监听GestureDetector 案例
以下只做长按和甩出(用户按下朝某一方向甩动手指)案例 OnGestureListener可以查看到更多的手势事件 案例 package com.qf.mobliesafe.activity; impo ...
- CSAPP缓冲区溢出攻击实验(下)
CSAPP缓冲区溢出攻击实验(下) 3.3 Level 2: 爆竹 实验要求 这一个Level的难度陡然提升,我们要让getbuf()返回到bang()而非test(),并且在执行bang()之前将g ...
- iOS应用启动时间
转自:iOS 知识小集 如果我们想知道程序启动的时间,则可以在工程的scheme中添加环境变量DYLD_PRINT_STATISTICS,如图1所示.这样在调试时,可以在控制台打印出程序启动过程中各个 ...
- Android studio - Failed to find target android-18
看了一下国外的解决方案,好多人也都遇到此类问题.看老外的聊天,由衷觉得着实的可爱,同时外国的月亮也不见得比国内的圆.以下是他们的对话(最后有一个小总结): I have a problem wit ...
- Objective-C's Init Method
初始化器在其他面向对象的语言中(比如Java)指的是构造器. Objective-C同样拥有对象构造器在init形式的方法中.不管如何,在Objc中这些方法没有什么特殊的行为. 按照惯例,程序猿在in ...
- Android图表库MPAndroidChart(十一)——多层级的堆叠条形图
Android图表库MPAndroidChart(十一)--多层级的堆叠条形图 事实上这个也是条形图的一种扩展,我们看下效果就知道了 是吧,他一般满足的需求就是同类数据比较了,不过目前我还真没看过哪个 ...
- Appium移动自动化框架初探
作者:cryanimal QQ:164166060 本文简要介绍了appnium自动化框架的架构.加载流程.支持语言.相关配置,以及元素定位工具等. 官方网站: http://appium.io Ap ...
- Spring常用配置(二)
OK,上篇博客我们介绍了Spring中一些常见的配置,上篇博客中介绍到的都是非常常见的注解,但是在Spring框架中,常见的注解除了上篇博客提到的之外,还有许多其他的注解,只不过这些注解相对于上文提到 ...
- Apache shiro集群实现 (一) shiro入门介绍
近期在ITOO项目中研究使用Apache shiro集群中要解决的两个问题,一个是Session的共享问题,一个是授权信息的cache共享问题,官网上给的例子是Ehcache的实现,在配置说明上不算很 ...