范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

三分钟让你知道什么叫SpringBean的生命周期

  1. Bean 的生命周期概述
  区别于普通的 Java 对象需要通过 new 创建对象,Spring 的 Bean 由 IoC 容器进行实例化、组装以及管理的。也就是说 Bean 的生命周期完全由 IoC 容器控制。
  Spring 容器只能管理 单例(singleton) 作用域的 Bean 的完整生命周期,对于 原型(prototype) 作用域的 Bean,Spring 容器只创建 bean 的实例后便会返回给用户,剩余的生命周期由用户控制。所以 Bean 的生命周期主要指的是 singleton 作用域 的 Bean。
  为什么要了解 Bean 的生命周期?
  通过了解 Bean 的生命周期可以了解 Bean 是什么时候被创建的,什么时候初始化,什么时候被销毁以及整个 Bean 的生命周期中哪些阶段可以使用哪些增加方法。
  这样在实际开发中,可以利用 Bean 的生命周期的指定时刻完成一些自定义的操作。同时面试中 Spring Bean 的生命周期也是常问的一个内容,所以很有必要了解一下。
  Bean 的生命周期主要包括四个部分实例化(Instantiation)属性赋值(Populate)初始化(Initialization)销毁(Destruction)
  以 AbstractApplicationContext 的 refresh() 方法为入口,AbstractAutowireCapableBeanFactory 的 doCreateBean 方法完成对 Bean 的实例化、属性注入以及初始化。(具体流程可以看 3.2 的具体流程梳理)
  以AbstractApplicationContext 的 close() 方法为入口,在 DisposableBeanAdapter 的 destory() 方法完成对 Bean 的销毁。(具体流程可以看 3.2 的具体流程梳理)
  2. 相关接口及方法
  Bean 的生命周期中使用到了 Aware 类型的相关接口、InitializingBean/DisposableBean 接口以及一些起到增强作用的接口。了解这些接口可以帮助大家更好地了解 Bean 的生命周期以及更好地拓展定制自己的 Bean 对象。2.1 各种 Aware 类型的接口
  实现 Aware 接口的目的是让程序可以拿到 Spring 容器的当前的运行环境(如当前 Bean 的名称、当前的 BeanFactory、当前的 ApplicationContext 等等资源)。这类接口的调用时机是在 Bean 实例化、属性注入之后,初始化之前。
  接下来列出一些常用的子接口,有兴趣的可以从源码中查看还有哪些接口(基本都是见名知意):
  BeanNameAware 接口
  接口中只有一个方法 void setBeanName(String name) 用于获取当前 Bean 的名称。
  BeanFactoryAware 接口
  接口中只有一个方法 void setBeanFactory(BeanFactory beanFactory) 用于获取当前的 BeanFactory。
  ApplicationContextAware 接口
  接口中只有一个方法 void setApplicationContext(ApplicationContext applicationContext) 用于获取当前的 ApplicationContext。
  2.2 InitializingBean/DisposableBean 接口
  实现InitializingBean/DisposableBean 接口能够实现自定义初始化方法以及销毁方法。这两个接口的调用时机分别在初始化阶段与销毁阶段。
  InitializingBean 接口
  接口中只有一个方法 void afterPropertiesSet() 用于自定义初始化行为,在属性注入阶段后执行。
  DisposableBean 接口
  接口中只有一个方法 void destroy() 用于自定义销毁行为,在销毁阶段执行。
  除了接口实现方式外,还有两种可以实现自定义初始化以及销毁的方式:使用 XML 配置文件 或者 Java 配置类 对 Bean 中的 init-method 与 destroy-method 属性进行配置(基于 Bean 自身的初始化和销毁)使用 注解 @PostConstruct 与 @PreDestroy 修饰方法(作用于servlet生命周期的注解)2.3 增强方法
  BeanFactoryPostProcessor 接口
  实现该接口可以增强的方面是:在 BeanFactory 已经初始化而 Bean 实例化之前调用该接口的方法可以修改或添加 Bean 的定义。所以该接口的调用时机是在 Bean 实例化之前。
  接口中只有一个方法 void postProcessBeanFactory(ConfigurableListableBeanFactory var1) 用于在 Bean 实例化之前修改 Bean 的定义。
  BeanPostProcessor 接口
  实现该接口能增强的方面是:在 Bean 实例化后,在初始化阶段的前后自定义行为。可以根据接口方法中的参数来筛选需要自定义行为的 Bean。该接口的调用时机是在 初始化阶段的前后。
  该接口有两个方法分别在初始化前和初始化后执行:postProcessBeforeInitialization(Object bean, String beanName):初始化前调用postProcessAfterInitialization(Object bean, String beanName):初始化后调用
  InstantiationAwareBeanPostProcessor 接口
  实现该接口能增强的方面是:在目标 Bean 实例化的前后可以自定义行为以及在属性注入前可以修改 Bean 的属性设置。
  该接口有三个方法(其实还有两个来自于继承 BeanPostProcessor 接口的方法):postProcessBeforeInstantiation(Class<?> beanClass, String beanName):在 Bean 实例化之前调用postProcessAfterInstantiation(Object bean, String beanName):在 Bean 实例化之后调用postProcessProperties(PropertyValues pvs, Object bean, String beanName):在 Bean 实例化之后,属性注入之前调用
  3. 浅谈生命周期的具体流程3.1 通过例子展示具体流程
  通过一个例子来体现 Bean 的生命周期 的具体流程以及相关接口对应的切入时机
  MyBean 类/**  * Bean对象  * @author 单程车票  */ public class MyBean implements InitializingBean, DisposableBean, BeanNameAware {      private Integer id;      public MyBean(Integer id) {         this.id = id;         System.out.println("过程3(实例化阶段中):调用构造方法,当前id为" + this.id + "(可以发现id此时并不是配置文件的1001,而是增强方法修改后的1002)");     }      public Integer getId() {         return id;     }      public void setId(Integer id) {         this.id = id;         System.out.println("过程6(属性注入阶段中):属性注入阶段,注入后id为" + this.id + "(可以发现id此时并不是配置文件的1003,而是增强方法修改后的1004)");     }      @Override     public void setBeanName(String name) {         System.out.println("过程7(属性注入阶段后):获取当前Bean的名称:" + name);     }      public void myInit() {         System.out.println("过程10(初始化阶段中):调用Bean自身属性 init-method 的初始化方法");     }      public void myDestroy() {         System.out.println("过程13(销毁阶段中):调用Bean自身属性 destroy-method 的销毁方法");     }      @Override     public void afterPropertiesSet() throws Exception {         System.out.println("过程9(初始化阶段中):调用 InitializingBean接口 的初始化方法");     }      @Override     public void destroy() throws Exception {         System.out.println("过程12(销毁阶段中):调用 DisposableBean接口 的销毁方法");     } } 复制代码
  实现 BeanFactoryPostProcessor 接口/**  * 对实例化前进行增强  * @author 单程车票  */ public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {     @Override     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {         GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("myBean");         ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();         constructorArgumentValues.addIndexedArgumentValue(0, 1002);         // 将原本配置文件配置的值1001改为1002(这里使用了ConstructorArgumentValues有兴趣的可以自行了解一下)         beanDefinition.setConstructorArgumentValues(constructorArgumentValues);         System.out.println("过程1(实例化阶段前): 调用 BeanFactoryPostProcessor.postProcessBeanFactory 方法进行增强,将id值改为1002");     } } 复制代码
  实现 BeanPostProcessor 接口/**  * 对初始化阶段前后进行增强  * @author 单程车票  */ public class MyBeanPostProcessor implements BeanPostProcessor {      @Override     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {         if ("myBean".equals(beanName)) {             System.out.println("过程8(属性注入阶段后,初始化阶段前):调用 BeanPostProcessor.postProcessBeforeInitialization 方法进行增强");         }         return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);     }      @Override     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {         if ("myBean".equals(beanName)) {             System.out.println("过程11(初始化阶段后):调用 BeanPostProcessor.postProcessAfterInitialization 方法进行增强");         }         return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);     } } 复制代码
  实现 InstantiationAwareBeanPostProcessor 接口/**  * 实现InstantiationAwareBeanPostProcessor接口  * @author 单程车票  */ public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {     @Override     public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {         if ("myBean".equals(beanName)) {             System.out.println("过程2(实例化阶段前):调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 方法进行增强");         }         return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);     }      @Override     public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {         if ("myBean".equals(beanName)) {             System.out.println("过程4(实例化阶段后):调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation 方法进行增强");         }         return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);     }      @Override     public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {         if ("myBean".equals(beanName)) {  // 对 Bean 再次修改 id 属性             PropertyValue propertyValue = pvs.getPropertyValue("id");             assert propertyValue != null;             propertyValue.setConvertedValue(1004);             System.out.println("过程5(实例化阶段后,属性注入阶段前):调用 InstantiationAwareBeanPostProcessor.postProcessProperties 方法进行增强,将id属性改为1004");         }         return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);     } } 复制代码
  XML 配置文件<?xml version="1.0" encoding="UTF-8"?>                                                                        复制代码
  测试类/**  * 测试类  * @author 单程车票  */ public class Application {      public static void main(String[] args) {         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");         MyBean bean = (MyBean) applicationContext.getBean("myBean");         ((AbstractApplicationContext) applicationContext).close();     } } 复制代码
  执行结果
  3.2 具体流程梳理
  通过上面的例子可以梳理出下面这张 Bean 的生命周期 具体流程图
  接下来从源码的角度对流程图的每一个部分进行剖析
  从源码看 BeanFactoryPostProcessor # postProcessBeanFactory() 在实例化前执行
  通过从 refresh() 入口进入按照上面图中的流程可以找到调用 postProcessBeanFactory() 的方法,该方法是在 invokeBeanFactoryPostProcessors(beanFactory) 进入的,而实例化阶段是从 finishBeanFactoryInitialization(beanFactory) 进入的,所以可以说明 BeanFactoryPostProcessor # postProcessBeanFactory() 要先于实例化执行。
  从源码看 InstantiationAwareBeanPostProcessor # postProcessBeforeInstantiation() 在实例化前执行
  通过上面的流程图可以找到调用 postProcessBeforeInstantiation() 的方法是在 resolveBeforeInstantiation(beanName, mbdToUse) 进入的,而实例化阶段是在 doCreateBean(beanName, mbdToUse, args) 进入的,所以可以说明 postProcessBeforeInstantiation() 要先于实例化执行。
  从源码看 实例化执行位置 与 属性注入执行位置
  实例化阶段发生在 AbstractAutowireCapableBeanFactory 的 createBeanInstance() 方法中。
  属性注入阶段发生在 AbstractAutowireCapableBeanFactory 的 populateBean() 方法中。
  从源码看 InstantiationAwareBeanPostProcessor # postProcessAfterInstantiation() 与 InstantiationAwareBeanPostProcessor # postProcessPropertyValues() 属性注入阶段前执行
  通过上面的流程图可以找到 postProcessAfterInstantiation() 与 postProcessPropertyValues() 在 populateBean() 属性注入方法内被调用。
  postProcessAfterInstantiation() 方法如果找到指定的 bean 就会返回 false,会直接返回不再执行后续方法内容,也就是说后续的属性填充和依赖注入就不会被执行,所以可以看出 postProcessAfterInstantiation() 执行在属性注入阶段前。postProcessPropertyValues() 方法同样发生在 属性填充 之前,如果返回null则不会执行后续的属性填充,如果不会为null,说明有额外添加的属性需要填充,后续方法会执行属性填充。
  从源码看 初始化阶段及其前后发生的调用
  根据上面的流程图可以找到初始化阶段进入的入口 initializeBean() 方法,具体代码如下图:
  先看 Aware 接口的调用除了上面 BeanXXXAware 接口的调用,如 ApplicationContextAware 接口的调用是发生在 applyBeanPostProcessorsBeforeInitialization 方法中的,也就是是通过 BeanPostProcessor的postProcessBeforeInitialization() 实现调用的,具体的可以自己跟一下源码。BeanPostProcessor 的两个实现方法这两个实现方法分别通过 applyBeanPostProcessorsBeforeInitialization 与 applyBeanPostProcessorsAfterInitialization 方法调用,也可以看出一个在初始化前一个在初始化后执行。invokeInitMethods 初始化方法invokeInitMethods 初始化方法中调用了 InitializingBean 的自定义初始化方法 与 Bean自身属性中的 init-method 指定的方法。
  从源码看 销毁阶段
  根据上面的流程图最终会找到 DisposableBeanAdapter 的 destory() 方法,具体代码如下:
  通过 destory() 方法也可以看到 销毁阶段 先执行 DisposableBean 的销毁方法,再执行 Bean 自身属性 destory-method 指定的方法。

杨幂,你就别装了吧01。hr最近午休时间,办公室里总有同事感叹,没有下饭剧可追。严格来说,剧还是有的,只是不够下饭。就拿杨幂和陈伟霆主演的斛珠夫人来说吧。这是两人继电视剧古剑奇谭后再次合作,一边是经39岁陈意涵平安生女!女儿正脸暂未曝光,孕期曾挺大肚炫一字马11月16日,据台媒报道,陈意涵已经顺利产下二胎女儿,母女平安。女儿暂时正脸还未透露,我们一起等待当事人官宣收获祝福吧!随即,内地主流娱乐媒体也发文证实此消息,让我们恭喜陈意涵!前薇娅的台前与幕后提到电商主播薇娅你有什么印象?是直播间常说的那句54321!上链接!还是她总能推荐心水好物,让人忍不住买买买所有人看到的都是镁光灯下光鲜亮丽的薇娅,但很少有人了解过,她的背后是什么唐朝灭亡的原因唐朝是中国历史上最为盛世的一个王朝也是把中国推向世界最巅峰时代的王朝,经济繁荣百姓富足国富兵强唐朝时期的中国真的可以说是世界的中心国,更是世界第一强国,但是再强大的王朝自然也有衰弱在清朝灭亡后,当年那些被关在宁古塔的重犯,最后都去哪儿了?在封建历史上,人从来都是紧俏货,当时的生产力低下,搞建设都要靠手工来完成。因此即便是那些犯了罪的人,能不执行死刑就不执行死刑,毕竟,人死后就没有任何意义了。在这种情况下,流放发配成火星殖民地模拟实验显示成员变得愈发自主且逐渐减少跟地面的联系次数本月早些时候,六个人开始了他们在一个沉浸式实验中的任期,这要么成为他们最大的梦想要么成为他们最糟糕的噩梦。据悉,他们生活在一个模拟的外星殖民地,同时被其建设者监控。这是Projec国家男篮12人首发预测来袭,是你心目中的阵容吗?先来回顾一下国家男篮集训名单(按球队)主教练杜锋广东队(4名)周鹏,任骏飞,徐杰,赵睿辽宁队(4名)韩德君,郭艾伦,赵继伟,张镇麟上海队(1名)王哲林浙江队(1名)吴前广厦队(2名晚上21点,国足世预赛出线再收惊喜转机,李铁的运气太好了北京时间11月16日,中国男足将会在晚上23点迎来12强赛小组赛第六场比赛,对手是澳大利亚。目前国足在小组内1胜1平3负排在小组第五位,小组出线形势急转直下,目前几乎只剩下理论上的王牌7常驻成员换牌,老成员一个不留王牌对王牌是最火的综艺之一,丝毫不输老牌综艺,可是第七季的消息一传出来,大家就有些接受不了了。本来大家还沉浸在第六季带来的欢声笑语中,可是没想到在里面的搞笑担当沈腾和贾玲居然不在了芭莎红毯宋茜好惊喜杨颖这次没得说,周笔畅和杨幂穿了个啥?一年一度的芭莎慈善夜又来了,可今年真的好不给力,既没有现场直播,更没有生图大乱斗,唯一不变的是那些一言难尽的明星红毯造型。周笔畅在红毯上常常剑走偏锋,这一次她又来了一招出其不意,穿11月16日A股猛料刚刚传出几条重要利好!涉及4板块今天有戏?聚焦A股市场每日重磅消息,为2亿散户点明投资方向!在阅读正文前,你必须知道一点没有几个主力资金会笨到在利好一出炉就将股价直线拉升到涨停,所以请股民朋友们耐心一点,让利好飞一会,也许
国家卫健委发布最新三高食养指南,记住这些,轻松吃掉三高!近日,国家卫生健康委制定发布多个成人慢性病食养指南其中包括成人高脂血症食养指南(2023年版)成人高血压食养指南(2023年版)成人糖尿病食养指南(2023年版)高血压高血糖高血脂简单易做的冰糖草莓,草莓和蓝莓,酸酸甜甜,不比北京糖葫芦差冰糖与草莓的巧妙结合,中和草莓微酸的味道,又避免吃冰糖过分甜腻的口感,还能起到清热去火,养肝明目的作用,真是春季不可多得的一道养生佳品。简单步骤1。准备草莓蓝莓。这个大家可以根据要哺乳动物社会组织与寿命有何关联?研究发现群居普遍比独居寿命长研究团队在中国野外对哺乳动物进行行为观察。朱平芬摄中新网北京2月1日电(记者孙自法)哺乳动物的社会组织与寿命之间有何关联?中国科学院动物研究所(中科院动物所)中科院动物生态与保护生煮年肉又到年底啦,想起小时候煮年肉的事,我们姐妹个个吃得满嘴流油,那个香呀,现在还能回味起来。小时候,一到腊月中旬,我爹就爱往街上跑,看看谁家杀猪了,瞧瞧谁家卖猪肉了,遇见好肉,买上一大外地朋友看过来,在西安吃面就去这20家!(排名不分先后)1钟楼吉庆巷柳巷面地址碑林区吉庆巷吉庆大厦B座2建设路刘二永香羊肉面地址碑林区建设西路242号3夏家什字坤坤菠菜面地址莲湖区夏家什字与北夏家什字路口南50米4测绘东哪些疤痕不适合用激光治疗?这5种情况,大家还是要慎重众所周知,疤痕是影响颜值的一个主要因素,脸上一旦有大面积的疤痕存在,无论哪一种都会影响人的美观和颜值。尤其是爱美的女性朋友,疤痕的存在完全是灾难现场。如今激光祛疤已经成为了有效且性初春穿风衣,这样搭配最美!嗨,各位小仙女们,大家好呀!初春,什么样的衣服更合适呢?如果你不知道穿什么,那么Lily建议你可以试试风衣外套,这种自带洒脱又肆意张扬的单品,穿起来可是超级有范的。若你要为自己选择话题重现面棋和复盘围棋回归了本来的模样本次LG杯决赛场,两位棋手用上了久违的棋盘,面对面进行手谈。中国围棋队主教练俞斌欣慰的表示,这才回归到围棋的本质。如果说近10年间中国围棋刮起青春风暴,日本和韩国棋手则在用自己的方背水一战!使用小球先发阵容收奇效,但内线隐患仍然不容忽视!本赛季西部的竞争格外激烈,除了休斯顿火箭和圣安东尼奥马刺以外,其他球队都具备冲击季后赛的实力和希望。这里面最让人意外的,可能就是来自西北赛区的俄克拉荷马雷霆和犹他爵士,赛季开始前外迪马利亚决赛打左路我以为主帅搞错了想参加下届美洲杯近日,阿根廷球星迪马利亚接受了阿根廷媒体TyC的专访,在采访中,34岁的迪马利亚回顾了自己的世界杯冠军之旅,并且谈到了自己的未来。决赛斯卡洛尼决定让你打左边路,意外么?对于自己的首德国杯拜仁近况状态欠佳,莱比锡攻击力表现稳定德国杯220345德甲11美因茨拜仁慕尼黑德甲1卡里姆奥尼斯莫的帽子戏法,帮助美因茨在周末的联赛52击败了波鸿,在德甲排名上升到11,也结束了球队5场连续不胜,周中的德国杯他们在主