我们知道,Spring容器具有对象的BeanDefinition来保存该对象实例化时须要的数据。
对象通过container.getBean()方法是才会初始化该对象。
BeanFactory
我们知道BeanFactory默认是懒载入的,换句话说,当我们请求对象a的时候,a本身还并没有被实例化,同一时候假设a还依赖b,那么b也还没有被初始化。
当我们显示的在代码里调用getBean("a")的时候,容器会先初始化b,再初始化a,然后把b注入到a中,当然,假设a或b实现了某些回调接口,就依据接口装备它,最后返还a。
ApplicationContext
与BeanFactory不同,ApplicationContext并非懒载入,当我们获得ApplicationContext的引用后,全部的bean就已经被实例化了。仅仅只是它会在启动阶段的活动完毕之后,紧接着调用注冊到该容器的全部bean定义的实例化方法getBean()。

另外,我们得知道container.getBean()方法仅仅是有可能会触发对象的实例化,我们仅仅是说"有可能"是由于,假设对象已经实例化了,那么调用getBean的时候就会返回缓存的那个对象(当然prototype型的除外)。
实例化过程如图:

实例化Bean对象

容器在内部实现的时候,採用“策略模式(Strategy Pattern)”来决定採用何种方式初始化bean实例。通常。能够通过反射或者CGLIB动态字节码生成来初始化对应的bean实例或者动态生成其子类。

在这里,大家能够查阅一下策略模式的使用。

org.springframework.beans.factory.support.InstantiationStrategy定义是实例化策略的抽象接口,其直接子类SimpleInstantiationStrategy实现了简单的对象实例化功能,能够通过反射来实例化对象实例,但不支持方法注入方式的对象实例化。CglibSubclassingInstantiationStrategy继承了SimpleInstantiationStrategy的以反射方式实例化对象的功能,而且通过CGLIB的动态字节码生成功能,该策略实现类能够动态生成某个类的子类,进而满足了方法注入所需的对象
实例化需求。默认情况下,容器内部採用的是CglibSubclassingInstantiationStrategy。
在这一步,问题不大。

只是有个东西得说明一下,第一步实例化的结果并非原生的bean,spring为了在第二步设置属性方便就用BeanWrapper对其做了包装。

BeanWrapper

BeanWrapper是个接口,事实上现类是BeanWrapperImpl。

Object provider = Class.forName("package.name.FXNewsProvider").newInstance();
Object listener = Class.forName("package.name.DowJonesNewsListener").newInstance();
Object persister = Class.forName("package.name.DowJonesNewsPersister").newInstance(); BeanWrapper newsProvider = new BeanWrapperImpl(provider);
newsProvider.setPropertyValue("newsListener", listener);
newsProvider.setPropertyValue("newPersistener", persister); assertTrue(newsProvider.getWrappedInstance() instanceof FXNewsProvider);
assertSame(provider, newsProvider.getWrappedInstance());
assertSame(listener, newsProvider.getPropertyValue("newsListener"));
assertSame(persister, newsProvider.getPropertyValue("newPersistener")); 

这是使用BeanWrapper设置属性的样例。
假设直接用反射呢?

        Object provider;try {provider = Class.forName("package.name.FXNewsProvider").newInstance();Object listener = Class.forName("package.name.DowJonesNewsListener").newInstance(); Object persister = Class.forName("package.name.DowJonesNewsPersister").newInstance(); Class providerClazz = provider.getClass(); Field listenerField = providerClazz.getField("newsListener"); listenerField.set(provider, listener); Field persisterField = providerClazz.getField("newsListener"); persisterField.set(provider, persister); } catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchFieldException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();}

呵呵,操蛋的try catch。

使用BeanWrapper的优点就在于,我们能够统一对属性的操作。

各种Aware接口

还记得,我们在前几节讲的关于,从bean中获得BeanFactory的引用的样例吗?

事实上这种接口还有几个:
org.springframework.beans.factory.BeanNameAware。

让bean知道自己在容器中究竟叫什么名字。
org.springframework.beans.factory.BeanClassLoaderAware。让bean知道是那个classloader载入的自己。

org.springframework.beans.factory.BeanFactoryAware。

让bean知道自己究竟在哪个"世界"里
上面的几个是针对beanFactory的。
相应于ApplicationContext的Aware接口有
org.springframework.context.ResourceLoaderAware 。 ApplicationContext 实 现 了Spring的ResourceLoader接口(后面会提及具体信息)。当容器检測到当前对象实例实现了ResourceLoaderAware接口之后,会将当前ApplicationContext自身设置到对象实例。这样当前对象实例就拥有了其所在ApplicationContext容器的一个引用。

org.springframework.context.ApplicationEventPublisherAware。ApplicationContext作为一个容器,同一时候还实现了ApplicationEventPublisher接口。这样,它就能够作为Appli- cationEventPublisher来使用。

所以,当前ApplicationContext容器假设检測到当前实例化的对象实例声明了ApplicationEventPublisherAware接口。则会将自身注入当前对象。

org.springframework.context.MessageSourceAware。ApplicationContext通过MessageSource接口提供国际化的信息支持,即I18n(Internationalization)。它自身就实现了MessageSource接口,所以当检測到当前对象实例实现了MessageSourceAware接口,则会将自身注入当前对象实例。

org.springframework.context.ApplicationContextAware。

假设ApplicationContext容器检測到当前对象实现了ApplicationContextAware接口。则会将自身注入当前对象实例。

BeanPostProcessor

这是什么东西?这是applicationcontext检測Aware接口并设置相关依赖的东西。

BeanPostProcessor的概念easy与BeanFactoryPostProcessor的概念混淆。但仅仅要记住BeanPostProcessor是存在于对象实例化阶段,而BeanFactoryPostProcessor则是存在于容器启动阶段,这两个概念就比較easy区分了。 
BeanPostProcessor接口有两个方法,例如以下:

public interface BeanPostProcessor {Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

两个方法
postProcessBeforeInitialization相应与图4-10中的BeanPostProcessor前置处理。
postProcessAfterInitialization相应与图4-10中的BeanPostProcessor后置处理。

BeanPostProcessor这个两个方法的參数都包括了当前要处理的bean,也就是说,在这两个方法里,我们能够对bean做不论什么事情。

通常比較常见的使用BeanPostProcessor的场景,是处理标记接口实现类,或者为当前对象提供代理实现。在图4-10的第三步中,ApplicationContext相应的那些Aware接口实际上就是通过BeanPostProcessor的方式进行处理的。当ApplicationContext中每个bean对象的实例化过程走到BeanPostProcessor前置处理这一步时,ApplicationContext容器会检測每个bean是否实现了之前注冊到容器的ApplicationContextAwareProcessor这个BeanPostProcessor的实现类。然后就会调用其postProcessBeforeInitialization()方法,检查并设置Aware相关依赖。
postProcessBeforeInitialization方法调用了invokeAwareInterfaces方法。

private void invokeAwareInterfaces(Object bean) {if (bean instanceof Aware) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}}}

注意ApplicationContextAwareProcessor这个类,实现了BeanPostProcessor,可是它并没有实现ApplicationContextAware这个接口。

*******************************************

下面为2016-04-20日更新

假设你在spring的doc文档里找ApplicationContextAwareProcessor,是找不到的,由于它并非public的

第二,看名字也知道这个类是作用于容器时applicationcontext的时候,假设我们单纯的使用beanfactory,是不会用到它的

第三,ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)----->refresh()---->prepareBeanFactory(beanFactory);

看到了吧,在这里手动注入的

那么我们自己写的beanpostprocessor怎样增加到容器里呢?

ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)----->refresh()-->registerBeanPostProcessors()

第四 和beanfactory的差别

applicationcontext是专门注入一个ApplicationContextAwareProcessor,来处理xxxaware接口的问题

beanfactory并没有一个单独的类来处理它,当然也就不须要注入这个类了

看AbstractAutowireCapableBeanFactory:

以上为2016-04-20日更新

*******************************************

自己定义BeanPostProcessor

为了演示BeanPostProcessor的强大功能,我们自己定义一个BeanPostProcessor
如果系统中全部的IFXNewsListener实现类须要从某个位置取得对应的server连接password。并且系统中保存的password是加密的,那么在IFXNewsListener发送这个password给新闻server进行连接验证的时候,首先须要对系统中取得的password进行解密,然后才干发送。

我们将採用BeanPostProcessor技术,对全部的IFXNewsListener的实现类进行统一的解密操作。

究竟哪些类须要加密解密呢?

我们用PasswordDecodable标记

public interface PasswordDecodable { String getEncodedPassword();   //从系统某处获得加密后的密码void setDecodedPassword(String password);  //将解密后的密码写入对象中
} public class DowJonesNewsListener implements IFXNewsListener,PasswordDecodable { private String password;           //解密后的密码public String[] getAvailableNewsIds() { // 省略 } public FXNewsBean getNewsByPK(String newsId) { // 省略 } public void postProcessIfNecessary(String newsId) { // 省略 } public String getEncodedPassword() { return this.password; } public void setDecodedPassword(String password) { this.password = password; } } 

然后实现我们自己的BeanPostProcessor。

public class PasswordDecodePostProcessor implements BeanPostProcessor { public Object postProcessAfterInitialization(Object object, String beanName) throws BeansException { return object; } public Object postProcessBeforeInitialization(Object object, String beanName) throws BeansException { if(object instanceof PasswordDecodable) { String encodedPassword = ((PasswordDecodable)object).getEncodedPassword(); String decodedPassword = decodePassword(encodedPassword); ((PasswordDecodable)object).setDecodedPassword(decodedPassword); }    return object; } private String decodePassword(String encodedPassword) { if(encodedPassword.length()<5)    //解码是 去掉前5个字符就是真正的password..return "";encodedPassword=encodedPassword.subString(5);return encodedPassword; }
}  

下来就是注冊这个PasswordDecodePostProcessor了。
对于BeanFactory类型的容器来说,我们须要通过手工编码的方式将对应的BeanPostProcessor注冊到容器。也就是调用ConfigurableBeanFactory的addBeanPostProcessor()方法,见例如以下代码:

ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(...));
beanFactory.addBeanPostProcessor(new PasswordDecodePostProcessor());
...
getBean(); 

假设是applicationcontext那就直接在xml注明就OK

 <beans> <bean id="passwordDecodePostProcessor" class="package.name.PasswordDecodePostProcessor"> <!--假设须要,注入必要的依赖--> </bean>   ...
</beans> 

http://guoliangqi.iteye.com/blog/635826 里面包括了一个自己定义BeanPostProcessor实现动态代理的样例

感谢glt

參考资料

http://guoliangqi.iteye.com/blog/635826
http://langgufu.iteye.com/blog/1499966
http://blog.csdn.net/wyabc1986/article/details/9415463

转载于:https://www.cnblogs.com/claireyuancy/p/7048041.html

spring揭秘 读书笔记 六 bean的一生相关推荐

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

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

  2. 3d游戏设计读书笔记六

    3d游戏设计读书笔记六 一.改进飞碟(Hit UFO)游戏: 游戏内容要求: 按 adapter模式 设计图修改飞碟游戏 使它同时支持物理运动与运动学(变换)运动 更改原 UFO_action 类 为 ...

  3. 【Spring MVC学习笔记 六】SpringMVC框架整合AJAX完成局部刷新

    本篇Blog介绍另一个常用的技术Ajax.虽然Ajax可以脱离SpringMVC去使用,但是SpringMVC对AJax有更好的支持 AJAX概念概述 AJAX即Asynchronous Javasc ...

  4. Android驱动开发读书笔记六

    第六章 Linux 驱动的工作和访问方式是 Linux 的亮点之一,Linux 系统将每一个驱动都映射成一个文件.这些文件称为设备文件或驱动文件,都保存在/dev目录中,由于大多数Linux驱动都有与 ...

  5. C专家编程--读书笔记六 运行时数据结构

    第六章 一.知识点 1.代码和数据的区别也可以认为是编译时和运行时的分界线.编译器的绝大部分工作都跟翻译代码有关:必要的数据存储管理的绝大部分都在运行时进行.(P121) 2."a.out& ...

  6. 《七步掌握业务分析》读书笔记六

    分析技术和呈现格式 词汇表 强有力沟通的一个重要内容是一致地使用术语和惯用语.每次谈话都涉及对术语的共同理解. 工作流图(也称为流程图.UNL活动图和过程图) 工作流程把一个或多个业务过程的细节可视化 ...

  7. Head First设计模式读书笔记六 第七章下 外观模式

    本文示例代码材料源自Head First设计模式 以前整理自己整理的链接: https://blog.csdn.net/u011109881/article/details/59153772 简介 H ...

  8. 你不知道的javaScript读书笔记(六)

    this全面解析 笔记: this的运行机制: (1) this是在运行时绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件.this的绑定和函数声明的位置没有任何关系,只取决于函数的调 ...

  9. Spring实战读书笔记 高级装配(1)

    一.条件化装配 1. 当你希望你的bean在特殊条件下才能装配时,比如在声明了特定的bean时,或者配置了特定的环境变量的时候.那么就可以使用 @Conditional注解,可以用在 @Bean注解下 ...

  10. css 揭秘-读书笔记

    css 揭秘 [希]Lea verou 著 css 魔法 译 该书涵盖7大主题,47个css技巧,是css进阶必备书籍,开阔思路,探寻更优雅的解决方案.这本书完全用css渲染出的html写成的(布局. ...

最新文章

  1. 宠物龟 扫地机器人_有宠物家庭必选 岚豹扫地机器人太实用了
  2. 2020-12-29 Linux查找某一关键字在哪个文件
  3. [转] android获取手机信息大全
  4. python 爬取网页内容 snmp_python通过SNMP协议收集服务器监控信息
  5. spss基本总结——聚类分析
  6. 基于等级保护2.0标准体系的医院信息化安全建设与研究
  7. php页面跳底部,监控页面滑到底部加载事件的jq
  8. 详解GBase 8c数据库安全之数据透明加密
  9. java小学生加减法_用java代码写随机加法算术题。 这些知识你不一定知道
  10. 和苗波玩吉他英雄,还有诺拉斯战士
  11. Maya Python脚本建模之随机生成多边形并设定目标限制
  12. 机遇与财富并存,一家网吧打造自己的客户数据库,后端疯狂盈利!
  13. magento 货币换算
  14. 链表的快速排序及冒泡排序
  15. 数字孪生相关概念阐述
  16. 派大星的面试题以及解决
  17. 软科计算机科学与工程专业,2019上海软科世界一流学科排名计算机科学与工程专业排名德蒙福特大学排名第201-300...
  18. mysql多表联合查询练习题
  19. sundancest201驱动_Toshiba Sundance ST201 based PCI Fast Ethernet Adapter 驱动程序下载——更新 Toshiba 软件...
  20. 社会财富分配问题模拟(蒙特卡洛思想)

热门文章

  1. 读《遇见未知的自己》有感
  2. AAAI'22 | 基于Profile信息的口语语言理解基准
  3. 李航:做本质的、严谨的、有意思的研究,纪念我的导师长尾真教授
  4. 篇章级关系抽取(Doc-RE)论文列表整理
  5. 你一直在用的Beam Search,是否真的有效?
  6. 【论文分享】ACL 2020 信息抽取与问答系统
  7. 使用BERT进行跨领域情感分析
  8. 【论文串烧】基于特定实体的文本情感分类总结(PART I)
  9. 三分钟教你如何PyTorch自定义反向传播
  10. 每日算法系列【LeetCode 719】找出第 k 小的距离对