IoC基础篇(一)--- Spring容器中Bean的生命周期
日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回。从调用XML中的Bean配置信息,到应用到具体实例中,再到销毁,Bean也有属于它的生命周期。
人类大脑对图像的认知能力永远高于文字,因此,闲言少叙,书归正传,上图先:
步骤很多,切莫惊慌,我们可以把上面的步骤归纳如下:
1-2:创建实例;
现在假设spring就是个容器,而配置文件中配置的bean属性才是我们真正需要的东西。创建实例就是说,我把配置文件中的bean信息取出来化作一个真正的bean并放到容器中。
3-4:注入依赖关系;
第3步是创建实例之后对实例作了一些处理,第4步是把xml中配置的bean属性值赋予给容器中的实例化之后的bean。
5:bean初始化之前的处理;
应用开发者需要把容器中实例化的bean拿出来用,这个拿出来的过程就是初始化(注意实例化与初始化的区别,instantiation 和initialization,分得清吗?英语没学好怪我咯?),第五步就是在初始化之前,对已经实例化的bean再作一定的处理。
6,7:初始化。
如果bean实现了InitializingBean,那么将调用InitializingBean的afterPropertiesSet()方法做一些初始化处理。如果没有实现InitializingBean,而是在配置文件中定义了init-method属性值,那么系统会找到init-method对应的方法并执行之,程序猿哥哥一般在这个方法里写一些初始化操作;
8:bean初始化之后的处理。
初始化之后在这个方法中再对bean进行修饰装点。
9,10:交给应用开发人员处理;
如果在<bean>中指定Bean的作用范围是scopt="prototype",那么系统将bean返回给调用者,spring就不管了(如果两个实例调用的话,每一次调用都要重新初始化,一个实例的修改不会影响另一个实例的值。如果指定Bean的作用范围是scope="singleton",则把bean放到缓冲池中,并将bean的引用返回给调用者。这个时候,如果两个实例调用的话,因为它们用的是同一个引用,任何一方的修改都会影响到另一方。)
11.bean用完之后;
对于scope="singleton"的bean,使用完之后spring容器会做一些处理,比如编写释放资源、记录日志等操作。
12.销毁;
调用配置文件中的销毁方法销毁实例。
光说不练假把式。来看实例:
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="jay" class="com.mesopotamia.bean_life_cycle.JayChou" init-method="myInit"destroy-method="myDestory"p:sex="男"p:girlFriend="蔡依林" p:profession="歌手,演员,导演,主持"scope="singleton"/> </beans>
上面是配置文件,取名为jayConfig.xml,注意bean中定义了init-method、destroy-method属性,翻阅上文查看这两个属性的作用。该bean还定义了scope属性,对应第9步。
在BeanFactory的bean生命周期中,第1、3、5、8步是由程序员自己扩展的。自己扩展类并在代码中注册使用。
下面看一个例子:
package com.mesopotamia.bean_life_cycle;import java.beans.PropertyDescriptor;import org.springframework.beans.BeansException; import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter{public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {if("jay".equals(beanName)){System.out.println("MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation"); } return null;}/**实例化Bean后,对Bean进行梳妆打扮*/public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if("jay".equals(beanName)){System.out.println("InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation");}return true;}//把Bean的配置值赋值给Bean实例的属性。public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)throws BeansException {if("jay".equals(beanName)){System.out.println("InstantiationAwareBeanPostProcessor.postProcessPropertyValues");}return pvs;}public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;} }
上面的类是继承了InstantiationAwareBeanPostProcessorAdopter的,而InstantiationAwareBeanPostProcessorAdopter这个适配器与是InstantiationAwareBeanPostProcessor的扩展类。
package com.mesopotamia.bean_life_cycle;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPostProcessor implements BeanPostProcessor{private Log log=LogFactory.getLog(MyBeanPostProcessor.class);public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("jay")){JayChou jay = (JayChou)bean;log.info("JayChou当前的女朋友是:"+jay.getGirlFriend());jay.setGirlFriend("昆凌");log.info("调用BeanPostProcessor的postProcessAfterInitialization处理后," +"JayChou的女朋友变成:"+jay.getGirlFriend());}return bean;}public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("jay")){JayChou jay = (JayChou)bean;log.info("配置文件中Jay的女朋友是:"+jay.getGirlFriend());jay.setGirlFriend("侯佩岑");log.info("调用BeanPostProcessor的postProcessBeforeInitialization处理后," +"Jay的女朋友变为:"+jay.getGirlFriend());}return bean;} }
上面的代码实现了BeanPostProcessor。InstantiationAwareBeanPostProcessor是实例化前后做的事情,BeanPostProcessor是初始化前后做的事情,它们之间应该存在着父子关系吧?当然是,从名字就能看出来前者是后者的扩展类,读者可以自己下载spring源码查看。这两个类定义好了需要注册才能使用(把它们注册到spring容器中使用),稍后再讲。这里先讲bean类:
package com.mesopotamia.bean_life_cycle;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean;public class JayChou implements InitializingBean,DisposableBean {private static Log log=LogFactory.getLog(JayChou.class);private String sex;private String profession;private String girlFriend;public JayChou(){log.info("调用JayChou的无参构造函数。杰伦出道啦。");}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public void setGirlFriend(String girlFriend) {this.girlFriend = girlFriend;}public String getGirlFriend() {return girlFriend;}public String getProfession() {return profession;}public void setProfession(String profession) {this.profession = profession;}public void afterPropertiesSet() throws Exception {this.profession="歌手";log.info("调用InitializingBean.afterPropertiesSet()," +"属性配置完毕了再做些善后工作。");}public void destroy() throws Exception {log.info("调用DisposableBean.destory(),销毁。。");}public void myInit() { this.girlFriend = "徐若瑄";log.info("通过调用配置文件初始化女朋友为:"+this.girlFriend);}public void myDestory() {System.out.println("调用myDestroy()。");}public String toString(){return "JayChou简介:" +" 性别:"+sex+" 职业:"+profession+" 女朋友:"+girlFriend;}}
这个bean实现了InitializingBean,DisposableBean,那么第六步和第11步就可以用得到了。
下面看Main方法类:
package com.mesopotamia.bean_life_cycle;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource;public class BeanLifeCycleMain {private static Log log=LogFactory.getLog(BeanLifeCycleMain.class);private static void LifeCycleInBeanFactory(){Resource res = new ClassPathResource("com/mesopotamia/bean_life_cycle/jayConfig.xml"); BeanFactory bf = new XmlBeanFactory(res);/**BeanFactory是ConfigurableBeanFactory的父类,且该父类没有这个添加方法,所以要转换。*/((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor()); //BeanPostProcessor((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyBeanPostProcessor()); JayChou jay = (JayChou)bf.getBean("jay");log.info("jay:"+jay.toString());// jay.setGirlFriend("温岚");JayChou jay2 = bf.getBean("jay",JayChou.class);jay2.setGirlFriend("温岚");log.info("jay2:"+jay2.toString());log.info("jay:"+jay.toString());log.info(jay == jay2);((XmlBeanFactory)bf).destroySingletons();}public static void main(String[] args) {LifeCycleInBeanFactory();} }
第17、18行是装载配置文件并启动容器(相关知识请自己脑补)。第21行和23行是注册事件,注册后才能正常使用。先看一下执行结果:
1 2015-11-07 22:01:26,907 INFO [main] (XmlBeanDefinitionReader.java:315) - Loading XML bean definitions from class path resource [com/mesopotamia/bean_life_cycle/jayConfig.xml] 2 MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 3 2015-11-07 22:01:27,068 INFO [main] (JayChou.java:18) - 调用JayChou的无参构造函数。杰伦出道啦。 4 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation 5 InstantiationAwareBeanPostProcessor.postProcessPropertyValues 6 2015-11-07 22:01:27,106 INFO [main] (MyBeanPostProcessor.java:28) - 配置文件中Jay的女朋友是:蔡依林 7 2015-11-07 22:01:27,106 INFO [main] (MyBeanPostProcessor.java:30) - 调用BeanPostProcessor的postProcessBeforeInitialization处理后,Jay的女朋友变为:侯佩岑 8 2015-11-07 22:01:27,106 INFO [main] (JayChou.java:49) - 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。 9 2015-11-07 22:01:27,106 INFO [main] (JayChou.java:61) - 通过调用配置文件初始化女朋友为:徐若瑄 10 2015-11-07 22:01:27,106 INFO [main] (MyBeanPostProcessor.java:16) - JayChou当前的女朋友是:徐若瑄 11 2015-11-07 22:01:27,107 INFO [main] (MyBeanPostProcessor.java:18) - 调用BeanPostProcessor的postProcessAfterInitialization处理后,JayChou的女朋友变成:昆凌 12 2015-11-07 22:01:27,110 INFO [main] (BeanLifeCycleMain.java:26) - jay:JayChou简介: 性别:男 职业:歌手 女朋友:昆凌 13 2015-11-07 22:01:27,110 INFO [main] (BeanLifeCycleMain.java:31) - jay2:JayChou简介: 性别:男 职业:歌手 女朋友:温岚 14 2015-11-07 22:01:27,110 INFO [main] (BeanLifeCycleMain.java:32) - jay:JayChou简介: 性别:男 职业:歌手 女朋友:温岚 15 2015-11-07 22:01:27,110 INFO [main] (BeanLifeCycleMain.java:34) - true 16 2015-11-07 22:01:27,110 INFO [main] (DefaultSingletonBeanRegistry.java:422) - Destroying singletons in org.springframework.beans.factory.xml.XmlBeanFactory@6e293a: defining beans [jay]; root of factory hierarchy 17 2015-11-07 22:01:27,111 INFO [main] (JayChou.java:55) - 调用DisposableBean.destory(),销毁。。 18 调用myDestroy()。
行1:加载xml。
行2:实例化之前处理了一些事情。
行3:duang!开始实例化,实例化当然首先要执行构造函数(这是美好世界的窗口)。
行4:实例化之后处理了一些事情。
行5:实例化之后注入属性值之前要调用这个函数。
行6:注入xml的属性值,可以看到是配置中的"蔡依林"。
行7:注入属性值后,随即又把女朋友这个属性的值改为了"侯佩岑"。
行8:属性配置完毕了做一些善后工作。在JayChou类的第48行可以看到,我把职业改为了"歌手",所以后面显示的职业都是"歌手",而不是配置文件中的"歌手,演员,导演,主持"。
行9:调用了配置文件中的init-method。通过<bean>的class属性找到这个类,再找到属性值对应的这个方法执行。行8和行9对应流程图表中的第六步和第七步,在此可以看到先执行第6步,后执行第七步。然而,行9是在配置文件中实现的,这正符合spring容器的宗旨,而行8的实现必须implements InitializingBean,给代码带来复杂度和污染,因此行8(也就是图表第六步)一般是不提倡的。
行10和行11是初始化之后做的事情,首先显示当前女朋友,在行9中已经改为徐若瑄。紧接着行11又把女朋友改为了昆凌。
行12-行15:看对应的代码就会发现,两个对象其实引用的是同一个地址,jay2修改了属性之后jay1也会跟着作改变,这就是singleton配置方式的作用。
行16是关闭容器。
行17和行18,一个是调用DisposableBean的销毁,一个是调用配置文件的销毁,利弊取舍与上文行9的叙述相同。
哥哥们姐姐们,那么如果把配置文件的scope属性改为"prototype"会发生什么呢?让我们看一下打印的日志:
1 2015-11-07 22:37:29,280 INFO [main] (XmlBeanDefinitionReader.java:315) - Loading XML bean definitions from class path resource [com/mesopotamia/bean_life_cycle/jayConfig.xml] 2 MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 3 2015-11-07 22:37:29,407 INFO [main] (JayChou.java:18) - 调用JayChou的无参构造函数。杰伦出道啦。 4 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation 5 InstantiationAwareBeanPostProcessor.postProcessPropertyValues 6 2015-11-07 22:37:29,444 INFO [main] (MyBeanPostProcessor.java:28) - 配置文件中Jay的女朋友是:蔡依林 7 2015-11-07 22:37:29,444 INFO [main] (MyBeanPostProcessor.java:30) - 调用BeanPostProcessor的postProcessBeforeInitialization处理后,Jay的女朋友变为:侯佩岑 8 2015-11-07 22:37:29,444 INFO [main] (JayChou.java:49) - 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。 9 2015-11-07 22:37:29,445 INFO [main] (JayChou.java:61) - 通过调用配置文件初始化女朋友为:徐若瑄 10 2015-11-07 22:37:29,445 INFO [main] (MyBeanPostProcessor.java:16) - JayChou当前的女朋友是:徐若瑄 11 2015-11-07 22:37:29,445 INFO [main] (MyBeanPostProcessor.java:18) - 调用BeanPostProcessor的postProcessAfterInitialization处理后,JayChou的女朋友变成:昆凌 12 2015-11-07 22:37:29,446 INFO [main] (BeanLifeCycleMain.java:26) - jay:JayChou简介: 性别:男 职业:歌手 女朋友:昆凌 13 2015-11-07 22:37:29,446 INFO [main] (JayChou.java:18) - 调用JayChou的无参构造函数。杰伦出道啦。 14 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation 15 InstantiationAwareBeanPostProcessor.postProcessPropertyValues 16 2015-11-07 22:37:29,447 INFO [main] (MyBeanPostProcessor.java:28) - 配置文件中Jay的女朋友是:蔡依林 17 2015-11-07 22:37:29,447 INFO [main] (MyBeanPostProcessor.java:30) - 调用BeanPostProcessor的postProcessBeforeInitialization处理后,Jay的女朋友变为:侯佩岑 18 2015-11-07 22:37:29,447 INFO [main] (JayChou.java:49) - 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。 19 2015-11-07 22:37:29,447 INFO [main] (JayChou.java:61) - 通过调用配置文件初始化女朋友为:徐若瑄 20 2015-11-07 22:37:29,448 INFO [main] (MyBeanPostProcessor.java:16) - JayChou当前的女朋友是:徐若瑄 21 2015-11-07 22:37:29,448 INFO [main] (MyBeanPostProcessor.java:18) - 调用BeanPostProcessor的postProcessAfterInitialization处理后,JayChou的女朋友变成:昆凌 22 2015-11-07 22:37:29,448 INFO [main] (BeanLifeCycleMain.java:31) - jay2:JayChou简介: 性别:男 职业:歌手 女朋友:温岚 23 2015-11-07 22:37:29,448 INFO [main] (BeanLifeCycleMain.java:32) - jay:JayChou简介: 性别:男 职业:歌手 女朋友:昆凌 24 2015-11-07 22:37:29,449 INFO [main] (BeanLifeCycleMain.java:34) - false 25 2015-11-07 22:37:29,449 INFO [main] (DefaultSingletonBeanRegistry.java:422) - Destroying singletons in org.springframework.beans.factory.xml.XmlBeanFactory@ce5b1c: defining beans [jay]; root of factory hierarchy
上面的日志是见证奇迹的时刻,当创建jay2对象时,从13行到21行,又进行了一次初始化的过程,而22行到24行发现,两个对象不相同了,这就是prototype的作用。
ApplicationContext中Bean的生命周期与BeanFactory类似,但是又有不同。对于InstantiationAwareBeanPostProcessor和MyBeanPostProcessor,BeanFactory需要在代码中注册方才能使用,而ApplicationContext只需要在xml中配置,spring会自动将它们注册到应用上下文中,这是二者最大的区别,也是为什么普遍使用ApplicationContext而非BeanFactory的原因。ApplicationContext是BeanFactory的扩展类。
spring当前在各大企业应用中广受青睐,spring融汇的java思想也堪称经典,因此笔者后面将继续跟广大猿猿一块学习探讨spring的精髓,对于文中的错误与不足,抑或是读者有一般人不告诉他的精辟见解,还望在评论中留言,一起学习。共勉。
转载于:https://www.cnblogs.com/fhwup/p/9082427.html
IoC基础篇(一)--- Spring容器中Bean的生命周期相关推荐
- IOC容器中bean的生命周期,iocbean生命周期
原文地址:http://www.bkjia.com/Javabc/1149957.html IOC容器中bean的生命周期,iocbean生命周期 一.Bean的生命周期 Spring IOC容器可以 ...
- IOC容器中bean的生命周期
一.Bean的生命周期 Spring IOC容器可以管理Bean的生命周期,允许在Bean生命周期的特定点执行定制的任务. Spring IOC容器对Bean的生命周期进行管理的过程如下: (1).通 ...
- SpringIOC容器中Bean的生命周期
SpringIOC容器 可以管理Bean的生命周期 Spring允许在Bean生命周期的特定点,执行定制的任务. SpringIOC容器中,Bean的生命周期如下: 1.通过构造器或工厂方法创建Bea ...
- 【面试题】Spring框架中Bean的生命周期
生命周期 1.实例化一个Bean--也就是我们常说的new一个对象: 2.按照Spring上下文对实例化的Bean进行配置--也就是IOC注入: 3.如果这个Bean已经实现了BeanNameAwar ...
- Spring框架中bean的生命周期
ean在Spring容器中从创建到销毁经历了若干阶段,每一阶段都可以针对Spring如何管理bean进行个性化定制. 正如你所见,在bean准备就绪之前,bean工厂执行了若干启动步骤. 我们对上图进 ...
- 再见面试官:你能说说 Spring 框架中 Bean 的生命周期吗?
首先简单说一下(以下为一个回答的参考模板) 1.实例化一个Bean--也就是我们常说的new: 2.按照Spring上下文对实例化的Bean进行配置--也就是IOC注入: 3.如果这个Bean已经实现 ...
- 阐述Spring框架中Bean的生命周期?
① Spring IoC容器找到关于Bean的定义并实例化该Bean. ② Spring IoC容器对Bean进行依赖注入. ③ 如果Bean实现了BeanNameAware接口,则将该Bean的id ...
- 面试问题:Spring中Bean 的生命周期
Spring Bean生命周期执行流程 在传统的 Java 应用中,Bean 的生命周期很简单,使用关键字 new 实例化 Bean,当不需要该 Bean 时,由 Java 自动进行垃圾回收. Spr ...
- (spring-第4回【IoC基础篇】)spring基于注解的配置
(spring-第4回[IoC基础篇])spring基于注解的配置 基于XML的bean属性配置:bean的定义信息与bean的实现类是分离的. 基于注解的配置:bean的定义信息是通过在bean实现 ...
最新文章
- 蕨叶形生物刷新生命史,动物界至少起源于5.7亿年前
- C语言的头文件和库文件(函数库)
- 使用HTML5 details,summary实现,展开,下拉,树的效果
- 阿里的 RocketMQ 如何让双十一峰值之下0故障
- c++ 获取操作的精确时间
- 从入门到入土:[SEED-Lab]-幽灵攻击|Spectre Attack Lab|详细说明|实验步骤|实验截图
- ios 微信分享重新编码链接_微信民众号IOS端复制链接失足,安卓端分享链接翻开只能进入首页等题目的处理...
- Sql Server 删除所有表
- 懒人版黑苹果mbr安装_黑苹果系统懒人版镜像|黑苹果超级镜像懒人版 OS X EI Capitan10.12.6 变色龙引导黑苹果cdr_ - 极光站...
- Directshow播放框架详解
- python初级数据分析师薪资_数据分析师的薪酬大约是多少?
- double比较大小
- 可变剪切(选择性剪接)rmats2sashimiplot可视化安装与使用
- 无人驾驶刚刚开始的未来
- AD1256之STM32程序——STM32测试高精度ADC篇(四)
- 桌面右下角任务栏图标消失问题解决
- 为达成与英文品牌的统一 蘑菇街更换域名为mogu.com
- Java split()用法,使用特殊字符要注意了
- Opencv之多目标追踪(基于Dlib库)
- Android的优化
热门文章
- BOOL ModifyStyleEx( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 );
- 世界各国google网址
- 【c++基础】int转string自动补零 前缀补零
- android 鼠标配置,Android 增加鼠标支持
- C++ 面向对象编程训练魔兽世界备战
- 【C语言】字符串和字符串数组的输入和陷阱
- 英语单词词性顺口溜_英语八大词性位置口诀
- C#项目中没有App.config文件,手动添加方法
- 建模杂谈系列226 流程与对象
- C语言经典习题之编写一个程序,找出1000以内所有的完数。