是新朋友吗?记得点击上方红字关注我喔~
昨天我们说了《冰箱不是“保险箱”,用了这么多年的冰箱,你真的用对了吗?》的第一部分——正确使用冰箱,包含冰箱的有效温度、嗜冷菌及冰箱不同温度区域食材的正确摆放三点。今天我们继续来说说科学合理使用冰箱的第二个方面——食品特性决定储存方式及期限。
冰箱不是保险箱,更不是储物箱,不是所有的食品都适合放到冰箱里
可以放的每种食品的自身特性又决定了它的储存方式和期限,通过合理的储存方式能使营养素的流失降到最低,避免交叉污染,特定的期限内食用能够保证食品的保鲜及安全性。加工后的预包装食品储存方式和保质期是非常明确的,我们可以直接从食品标签上获取,按照要求严格执行,需要冷藏或者冷冻的食品根据前面讲的摆放要求放在冰箱适合的位置上就可以了,在保质期内食用都是安全的。
不过,考虑到实际情况,我们更建议尽早食用。比如速冻食品,超市里的冰柜频繁被人开启,保存温度基本上都是不达标的,那么就会对食品有一定影响,所以购买的时候我们特别建议不要拿最上面的,越下面保存温度越接近有效低温温度,而且很多家庭冰箱零下18℃也不是那么的稳定,速冻食品在购买后的3个月内食用是最推荐的。
新鲜的各种食品根据其本身的特性,不同的储存方式对营养素流失的速度和保鲜期的长短都是不同的。蔬果采摘、肉类宰杀之后,营养素的流失就已经开始,冰箱的有效低温环境是可以延缓部分食品营养流失的速度。
那么到底哪些营养素会流失或者发生改变呢?
我们要知道,在所有的营养素中,最容易流失的就是维生素c、b1、叶酸等水溶性维生素,比如绿叶蔬菜,室温储存24小时,维c的损失高达70%以上,天热的环境下损失90%以上。但是如果用保鲜膜包裹好放在4℃的冰箱里,3天才会损失70%。而肉类和水产品类食品最容易出现脂肪氧化,会使这类食物中的油脂失去营养价值,甚至产生有毒有害的物质。脂肪氧化的反应不怕冷,所以,即使是冷冻的肉类和海产品类,时间长了,口感都会降低,同时随着时间的延长,维生素损失,蛋白质、氨基酸氧化,整体营养价值大打折扣。
所以动物食品的储存期是由脂肪性能决定的,不同种类的肉,储存期也不同。比如,牛肉的脂肪比较稳定,但猪肉和海产品的脂肪就不稳定,所以家庭囤肉的时候,牛肉的储存期长,可以晚点吃,先吃鱼肉和猪肉。
根据食品的特性,并不是所有的食品都适合放在冰箱里低温冷藏,低温环境对这些食物反而是不利的。总结一下,主要是蔬菜、水果和面食中比较多。
蔬菜中常见的番茄、黄瓜、茄子、辣椒、胡萝卜、西葫芦、南瓜、紫薯、红薯、山药、土豆、大蒜、洋葱、生姜等,都不适合放到冰箱里,常温阴凉处储存就可以了,这些食物怕冷,当温度太低时会发生冷害,进而风味变差,色泽变暗,严重时出现半透明状的冻害,但是如果是切了以后的食材,比如切了一半的洋葱、胡萝卜,还是建议用保鲜膜全部包裹或者放在密闭的保鲜盒内放到冰箱里冷藏,一定要尽早的食用。
水果主要是热带水果,大部分热带水果适宜存储温度在10 ℃左右,比如香蕉、芒果等;也有部分热带水果是需要低温保存的,比如最常见的荔枝和火龙果,高温会加速水果代谢,冰箱里的高温储存区适合放这一类的水果。如果购买了面包、馒头、包子等淀粉类食物,最好不要放在冰箱里,不然拿出来以后馒头、面包都会变得又干又硬,口感特别差,这是因为4℃是淀粉老化的最佳温度。如果实在买的太多了,就放在冰箱的冷冻室里。
可以放在冰箱里的食材,都是有固定保鲜期的,在保鲜期内食用,即安全又营养。以冰箱冷藏为例,看看常见食材的保鲜期,让大家做到心里有数。大部分叶菜的保鲜期只有2~3天,比如青菜、韭菜,部分可以保鲜5天,比如生菜;根茎菜保鲜期是4~8天左右,比如莲藕4天,西兰花7天;新鲜菌菇类、豆制品、新鲜的肉及水产品类食品的保鲜期都只有2天左右,水果中除了苹果的保鲜期可以长达20天,其他水果比如草莓、葡萄的保鲜期一般都是在5天左右。剩米饭在密封条件下,保鲜期是3天左右。这样的冷藏时间是科学的,大家也可以翻查一下自己家的冰箱,看看有多少食品已经过了保鲜期了。
除了注意保鲜期,食品的储存方法也非常重要
如果方法错误,会加速各种营养素的流失和食物变质的速度。现在很多人购买的新鲜食材是塑料袋密封状态,拿回家以后就直接放到冰箱里或者拆了包装直接将食材裸露在冰箱里。这都是不正确的,密封的状态不适合蔬菜瓜果类食材的储存,而完全裸露的状态会导致催熟或者交叉污染。蔬菜和蔬果中水分含量特别高,如果完全密封,蔬果中蒸发的水分会在袋子内结成水珠,使微生物容易生长,还会因为袋内缺少氧气,使蔬果不能呼吸进一步造成腐烂,浪费食材。为了避嫌交叉污染,建议每种食材都应该单独用保鲜袋或塑料袋装起来,但是袋口不要封的太死,在袋子上多扎几个小孔,蔬菜可以保存2~3天左右。如果是蒜黄、韭菜等易腐烂的食材,摘掉烂叶、坏叶,用厨房纸包裹后再放进塑料袋里面,扎几个小孔,也可以保存2~3天左右。蔬菜和水果一定要放在冰箱的最下面的保湿抽屉里单独存放。而肉类、鱼虾类和鸡蛋,无论是生是熟,是冷藏还是冷冻,都必须做到密闭保存,冷藏要用食品保鲜袋或保鲜盒密闭保存,冷冻需用食品保鲜袋提前做好每顿的分装,并排掉多余的空气,做到密闭保存。
最后给大家一些小建议和小窍门,冰箱必须要定期的清洗,比如一周清洗一次。为了防止忘记食材的购买时间,可以在冷冻食材的包装上用记号笔标注食材的名称、购买日期和保质期;冷藏区的食材可以使用冰箱贴,记录每种食材购买的具体时间,也可以加上保存期。这样使用冰箱才更安全。
八种菜隔夜万万吃不得!尤其是第三种,千万要注意!
2017-07-04
半困
郑州微公交
为20万郑州公交乘客求福利
小编微信:15639006006,欢迎骚扰
大家都知道晚上炒的菜放到第二天吃就是“隔夜菜”,但要是早上炒的晚上吃,就不算“隔夜”了吧,其实不然。
所谓的隔夜菜,只是更直观的说法,其实只要放置超过8小时以上的菜,都跟隔夜菜是一回事。
那到底有哪些隔夜菜是吃不得的呢,狗哥为大家整理了一份清单,这关系到我们每个人的健康,一定要认真对待哟~
?隔夜八不吃?
1、绿叶菜
在所有饮食——水、肉、蔬菜、水果中都不可避免地含有硝酸盐和亚硝酸盐,其中以茎叶蔬菜的含量最高。
部分绿叶类蔬菜中含有较多的硝酸盐类,煮熟后如果放置的时间过久,在细菌的分解作用下,硝酸盐便会还原成亚硝酸盐。
亚硝酸盐本身并不是致癌物,而是亚硝酸盐在人体内可能会转化成亚硝胺,亚硝胺是一种致癌物。 ?
因此,如果同时购买了大量蔬菜,应该先吃叶菜类的,比如大白菜、菠菜等。
如果准备多做一些菜第二天热着吃,应尽量少做茎叶类蔬菜,而选择瓜类蔬菜。
重点提示:
时值夏天,如果绿叶菜实在没吃完,就不要隔夜了,无论多心痛,请倒垃圾桶吧,尤其是菠菜和芹菜,硝酸盐含量都比较高,再次加热后很容易转化为亚硝酸盐,再进入人体可就不好了!
2、海鲜
螃蟹、鱼类、虾类等海鲜,隔夜后会产生蛋白质降解物,损伤肝、肾功能。
重点提示:
如果实在买多了,可以把生海鲜用保鲜袋或保鲜盒装好,放入冰箱冷冻,下次再烹调。
3、鸡蛋(最常见)
如果鸡蛋没有完全熟透,那么未熟的蛋黄隔夜之后食用,在保存不当的情形下,营养的东西容易滋生细菌,造成例如肠胃不适、胀气。
但是如果鸡蛋已经熟透,而且以低温密封保存得当,一般没有问题。
重要提示:
但是鸡蛋还是尽量不要隔夜吃,即煮即吃比较好。
4、银耳蘑菇
不论是野生的还是人工栽培的银耳、蘑菇等,都容易残留很多硝酸盐。银耳蘑菇之类的菜品本身就有硝酸盐,如果放置时间过久,硝酸盐会更多。
重点提示:
如果现煮的银耳和蘑菇没有吃完,就只能忍痛扔掉,否则可能引起肠胃不适。
5、汤汁
熬汤费时费力,人们往往熬一大锅,一连吃好几天。剩汤如果长时间盛在铝锅、铁锅内,会析出对人体有害的物质。
重点提示:
存汤的最好办法是,汤里不要放盐之类的调味料,煮好汤用干净的勺子盛出当天要喝的,喝不完的,最好是用瓦锅或保鲜盒存放在冰箱里。
6、卤味菜
预防食物中毒,春夏季节吃卤味不要隔夜。
重点提示:
即使放在冰箱里的食物,也并非绝对“保险”。冰箱里易滋生霉菌,还有嗜冷菌等,而这些对人体健康都是不好的!
7、豆浆
鲜榨豆浆保质期很短,常温下2-4小时内必须喝完,否则菌落数量会急剧增加引起变质!
重点提示:
豆浆最好是现榨现喝,或是将煮沸的豆浆冷却后,放在冰箱里密封保存,以防变质。在冰箱里冷藏的鲜榨豆浆,也不宜存放过久,超过12小时以上的,最好也不要再喝了。
8、土豆
土豆是个好东西,但是也不能隔夜后再加热使用,这样不仅会造成土豆营养成分的流失,还会对我们的身体造成损害。
重点提示:
如果放置过久再食用,土豆中的毒素会伤害到肠道粘膜,从而引起肠道不适和消化功能慢性障碍。
除了这些隔夜菜,
其他的菜隔夜还是能吃的,
怎么处理才是健康、安全的呢?
隔夜菜安全食用法则
1?凉透后立即放入冰箱
晾凉再放是因为热食物突然进入低温环境,食物的热气会引起水蒸气凝结,促使霉菌生长,从而导致冰箱里的食物霉变。
凉透后,要及时放入冰箱,即使在冬季,也不要长时间放在外面,因为冰箱有一定的抑菌作用。
2?分开储存
分开存储可以避免细菌交叉污染。还需要用干净的容器密闭储存,如保鲜盒、保鲜袋,或者把碗盘包裹上一层保鲜膜。
3?隔夜汤存放别加调料
如果汤要隔夜,最好的保存方法是,汤里不要放盐类调味料,汤煮好后用干净的勺子舀出当天要喝的量,余下的用瓦锅存放于冰箱中。
剩汤长时间盛在铝锅、不锈钢锅内,易发生化学反应,故应盛放在玻璃或陶瓷器皿中。
4?吃前回锅热透
除了合理储存,回锅加热也是保障健康的关键。剩菜在冰箱里储存,吃之前一定要高温回锅,把菜整体加热到100℃,保持沸腾3分钟以上。
因为低温只能抑制细菌繁殖,不能彻底杀死细菌。
5?两天内吃完
有研究显示,剩饭在常温下超过6小时,亚硝酸盐含量会直线上升。就是放在冰箱,冰箱也只是起到抑菌作用,不能杀菌,细菌仍会慢慢滋生增长,剩饭菜一般2天以内尚可食用,超过3天最好倒掉。
通常放在冰冻柜的剩饭菜2周都不会变质,但也建议一周内食用完。
6?定期清洁冰箱
不少家庭的冰箱没定期清洁,各类细菌(尤其是大肠杆菌)会在湿冷环境中滋生。取出冷藏食物,立即食用,细菌会入侵胃肠,引发“冰箱性胃肠炎”。
因此,三个月左右,冰箱要做一次“大扫除”。
现在上班族都流行带饭去公司吃,
那如何带饭才能更健康呢?
?关于盒饭菜肴?
素菜:别带绿叶菜。尤其是青菜、菠菜和韭菜,蔬菜类还是尽量带像莲藕、土豆、萝卜、香菇等,当然菌菇类蔬菜是比较好的选择。
荤菜:带牛鸡肉,别带海鲜。最好选择优质蛋白质的肉类,可选择不饱和脂肪酸含量少的牛羊肉、鸡肉,猪肉的不饱和脂肪酸则相对较多,最好少带。
虽然鱼肉和虾肉能提供丰富的优质蛋白质,但也最好不选。一方面鱼和海鲜隔夜后易产生蛋白质降解物,会损伤肝、肾功能;另一方面,经过微波炉加热的鱼和海鲜,很难保持原有色香味,外相会影响食欲。
关于保鲜时间
饭最好早上现煮。剩饭的保存时间尽量缩短在5至6小时内,要彻底加热后食用。剩米饭很容易引起食物中毒,但大多剩饭看上去没有异样,让人大意。
菜做好后自然冷却再盖上便当盒放进冰箱,但海鲜、绿叶菜、凉菜隔夜后易变质,最好第二天别吃。
关于盛饭盒子
最好是瓷质或玻璃材料,如果是塑料盒,盒底有一个三角形里带“5”的符号,三角形下还写有“pp”(聚丙烯缩写),则可以在微波炉内加热。
微波炉适用的塑料餐盒也可使用,其他塑料盒最好不要选,以免在微波炉加热过程中释放有毒物质。
关于微波炉加热
米饭加热前喷点水再加盖,如果食物中缺少水分,则加热烹饪效果会受到影响。
为防止便当食物中水分逃逸,我们可采取一些措施:如放入食物的容器应加盖后烹饪,或用保鲜膜包裹后加热。这对含水量少的食物尤显必要。
小心使得万年泉,为了自己和家人的健康
提醒一下总没坏处~
今日话题
据说从不剩饭的最后都成了胖子
真的假的?
来源:网络。爱游戏平台的版权归原作者所有,如有侵权请联系微信15639006006删除。
长按关注 路上读一读图文
夏天喝热水真的比喝冷饮好吗?刷牙前千万别沾水,更不要一起床就刷牙!原来我们一直都刷错了...出汗的10大惊人好处!看完我默默把空调关了…家长注意!你家孩子还在玩这个吗?暑假已经有人出事了!
转载于:https://my.oschina.net/u/3577266/blog/1153858
文章目录
1 注解启动分析1.1 @springbootconfiguration1.2 @componentscan1.3 自动装配@enableautoconfiguration1.3.1 @autoconfigurationpackage1.3.2 @import({autoconfigurationimportselector.class})1.3.2.1 autoconfigurationimportselector.class1.3.2.2 getautoconfigurationentry方法1.3.2.3 loadfactorynames方法1.3.2.4 loadspringfactories方法1.3.2.5 cache探秘1.3.2.6 getautoconfigurationentry再探1.3.2.7 自动装配本质1.3.2.8 自动装配总结
1.3.3 自动装配用到类总结
2 springapplication引导启动2.1 springapplication—创建引导启动的实例2.2 run()—开始引导启动2.2.1 new stopwatch()—创建计时器2.2.2 configureheadlessproperty()—配置headless模式2.2.3 springapplicationrunlistener.start()—获取监听器,启动监听2.2.4 prepareenvironment()—准备环境,创建configurableenvironment对象2.2.5 printbanner()—打印横幅2.2.6 createapplicationcontext()—创建应用程序上下文并加载bean2.2.7 preparecontext()—准备applicationcontext2.2.8 refreshcontext()—刷新上下文2.2.8.1 preparerefresh()—准备刷新2.2.8.2 preparebeanfactory()—准备beanfactory2.2.8.3 postprocessbeanfactory()—后置处理beanfactory2.2.8.4 invokebeanfactorypostprocessors()—实例化并调用beanfactorypostprocessor2.2.8.5 registerbeanpostprocessors()—注册bean后置处理器2.2.8.6 initmessagesource()—初始化messagesource2.2.8.7 initapplicationeventmulticaster()—初始化applicationeventmulticaster2.2.8.8 onrefresh()—刷新应用程序2.2.8.9 registerlisteners()—注册监听器2.2.8.10 finishbeanfactoryinitialzation()—初始化容器中的bean2.2.8.11 finishrefresh()—完成刷新
2.2.9 afterrefresh()—留给子类的钩子函数
2.3 启动完成2.4 准备运行
3 总结
spring boot为我们提供了一种极简的项目搭建方式,看一下spring boot项目的启动类:
@springbootapplication
public class application {
public static void main(string[] args) {
springapplication.run(application.class,args);
}
}
1 注解启动分析
注解启动分析,就是说的@springbootapplication 首先看一下@springbootapplication这个组合注解,除去元注解外,它还引入了其他三个重要的注解:
@springbootconfiguration
@enableautoconfiguration
@componentscan
1.1 @springbootconfiguration
@target(elementtype.type)
@retention(retentionpolicy.runtime)
@documented
@configuration
public @interface springbootconfiguration {
}
从源码可以看到,其实@springbootconfiguration并没有额外功能,它只是spring中@configuration的派生注解,用于标注配置类,完成bean的配置与管理 @springbootconfiguration只是spring标准@configuration批注的替代方法。 两者之间的唯一区别是@springbootconfiguration允许自动找到配置 应用程序应该只包含一个@springbootconfiguration并且大多数惯用的 springboot 应用程序将从@springbootapplication继承它
1.2 @componentscan
spring中的注解,用于包的扫描,并把声明了特定注解的类交给spring的ioc容器
1.3 自动装配@enableautoconfiguration
springboot根据应用所声明的依赖来对spring框架进行自动配置,其中包括两个重要注解:@autoconfigurationpackage和@import({autoconfigurationimportselector.class})
1.3.1 @autoconfigurationpackage
@autoconfigurationpackage:该注解上有一个@import({registrar.class}) 注解,其中registrar类的作用是将启动类所在的包下的所有子包组件扫描注入到spring容器中,因此这就是为什么将controller、service等包放在启动类的同级目录下的原因
1.3.2 @import({autoconfigurationimportselector.class})
1.3.2.1 autoconfigurationimportselector.class
spring boot有中一个非常重要的理念就是约定大于配置。而自动配置这一机制的核心实现就是靠@enableautoconfiguration注解完成的 可以看出,在@enableautoconfiguration注解中,使用@import导入了autoconfigurationimportselector这个类,实现了importselector接口的selectimports()方法。spring中会把selectimports()方法返回的string数组中的类的全限定名实例化为bean,并交给spring容器管理
1.3.2.2 getautoconfigurationentry方法
查看其中的getautoconfigurationentry方法: 在执行完getcandidateconfigurations后,把众多类的全限定名存储到了一个list中 springfactoriesloader这个类非常重要,属于spring框架的一种扩展方案,提供一种了配置查找的功能支持。其主要功能就是读取配置文件meta-inf/spring.factories,决定要加载哪些类 当然,并不是所有spring.factories中的类都会被加载到spring容器中,很多情况下需要按照需求所需的情况引入,依赖条件注解@conditional进行判断。例如servletwebserverfactoryautoconfiguration类 只有在classpath下存在servletrequest这一类时,才将servletwebserverfactoryautoconfiguration作为配置类导入spring容器中
1.3.2.3 loadfactorynames方法
进入loadfactorynames方法: 这个方法非常简短,因为他调用了真正实现的方法:loadspringfactories 这一行return代码复制在下面:
loadspringfactories(classloader)
.getordefault(factorytypename, collections.emptylist());
可以分析得出:loadspringfactories方法的返回值又调用了一个getordefault方法,这明显是一个容器类的方法,目的是从容器中拿点东西出来
就此推测:loadspringfactories返回了一个包含我们需要的config全类名(字符串)的集合容器,然后从这个集合容器中拿出来的东西就是我们的configurations
1.3.2.4 loadspringfactories方法
看这个loadspringfactories方法:
它确实返回了一个容器:map
接下来我们继续思考:我们来的目的是获取configurations,所以无论你做什么,必须得读取配置文件,拿到configurations 于是我们在try方法体中果然发现了这个操作:
获取了一个路径urls,那么这个路径是否就是我们前面验证的meta-inf/spring.factories呢? 查看静态常量factories_resource_location的值:
继续往下看,果然他遍历了urls中的内容,从这个路径加载了配置文件:终于看到了我们熟悉的loadproperties方法!
那我们大概就知道了,他确实是通过找到路径,然后根据路径读取了配置文件,然后返回了读取的result
这就是loadfactorynames方法的内部实现。
1.3.2.5 cache探秘
细心地朋友已经发现了玄机,隐藏在loadfactorynames方法的开头和结尾: 它是从cache缓存中取出来的 根据下面的if判断,如果从缓存中读取出来了result,并且result的结果不为空,就直接返回,不需要再进行下面的读写操作了,这样减少了磁盘频繁的读写i/o 同理,更新完所有的配置文件资源之后,退出时也要更新缓存。
1.3.2.6 getautoconfigurationentry再探
关键部分已经过去,重新审视一下遗漏的内容: 还记得getautoconfigurationentry方法吗?
我们最后来研究一下这个类除了getcandidateconfigurations还干了哪些事情:
removeduplicatesconfigurations.removeall(exclusions)
可以看到,这里对加载进来的配置进行了去重、排除的操作,这是为了使得用户自定义的排除包生效,同时避免包冲突异常,在springboot的入口函数中我们可以通过注解指定需要排除哪些不用的包: 例如我不使用rabbitmq的配置包,就把它的配置类的class传给exclude
@springbootapplication(exclude = {rabbitautoconfiguration.class})
1.3.2.7 自动装配本质
springboot自动装配的本质就是通过spring去读取meta-inf/spring.factories中保存的配置类文件然后加载bean定义的过程。 如果是标了@configuration注解,就是批量加载了里面的bean定义 如何实现自动:通过配置文件获取对应的批量配置类,然后通过配置类批量加载bean定义,只要有写好的配置文件spring.factories就实现了自动。
1.3.2.8 自动装配总结
spring boot的自动装配特性可以说是spring boot最重要、最核心的一环,正是因为这个特性,使得我们的生产复杂性大大降低,极大地简化了开发流程
spring boot自动装配详细流程图: 自动装配部分转载于:https://mp.weixin.qq.com/s/1u_pyu1cqbyrgelrbo8qyw
1.3.3 自动装配用到类总结
最后,总结一下整个自动装配的过程:
引入 meta-inf/spring.factories 配置文件,在 enableautoconfiguration 对应的 value 中配置需要引入的配置类。启动类增加 @enableautoconfiguration 注解,@springbootapplication 已经自带。@enableautoconfiguration 注解中通过 @import 标注了 autoconfigurationimportselector 类。autoconfigurationimportselector 继承了 deferredimportselector 接口,在 spring 生命周期处理 beanfactorypostprocessors 的时候会对配置信息进行后置处理,这是会调用到 autoconfigurationimportselector.process 方法。process 方法中会读取 meta-inf/spring.factories 配置文件中的内容为 key-value 形式,读取完后值返回 key = enableautoconfiguration 对应的配置类信息,保存到 autoconfigurationentries 中。autoconfigurationgroup#selectimports 方法返回排序、筛选后的配置类信息,然后依次遍历,递归调用 processimports, 根据这些配置类的全路径名读取并注册在 spring 容器中。
2 springapplication引导启动
springapplication类是用来执行spring框架启动的引导类。有两种方式可以进行启动引导:
通过静态方法 springapplication.run启动。先创建 springapplication实例,在调用的实例方法 run进行启动。
无论是以上哪种方式,最终都是通过创建springapplication实例,在调用run()启动
2.1 springapplication—创建引导启动的实例
springapplication提供了一个简单的方式以启动spring boot程序,查看springapplication.run方法调用: 在此创建了一个springapplication的实例,并调用了它的run方法 在创建实例的过程中,会根据用户输入和工程环境做一些基础配置,供之后引导启动中使用:
设置资源加载器resourceloader和primarysources,用于将资源加载到加载器中从类中加载initializer和listener放在集合判断当前项目类型是什么? 提供了none,servlet,reactive 三种类型备选使用springfactoriesloader查找并加载所有可用的applicationcontextinitializer使用springfactoriesloader查找并加载所有可用的监听器applicationlistener推断并设置main方法的定义类设置是否为web环境(先确认用户是否指定,未指定则根据工程目录下是否有servlet相关环境)从工程环境中决定主入口的类
2.2 run()—开始引导启动
springapplication完成初始化后,调用run方法,下面对run方法中核心代码进行分析: 按照图中标注序号进行分析:
spring监听器的使用,要获取这些监听器的对象,就要知道其全路径。通过springfactoriesloader查找spring.factories获得,之后再调用它们的started()方法。创建并配置当前spring boot应用将要使用的environment,根据监听器和默认应用参数来准备所需要的环境。打印banner创建spring应用上下文。根据之前推断的项目类型,决定该为当前springboot应用创建什么类型的applicationcontext并创建完成。准备应用上下文,首先将之前准备好的environment设置给创建好的applicationcontext使用。 然后遍历调用所有applicationcontextinitializer的initialize方法来对已经创建好的applicationcontext进行进一步的处理。 最后,遍历调用所有springapplicationrunlistener的contextprepared()方法。这里最终调用了spring中abstractapplicationcontext的refresh方法,可以说这个refresh方法是spring中最重要的方法之一,完成了bean工厂创建,后置管理器注册,bean实例化等最重要的工作。这一步工作完成后,spring的ioc容器就完成了。如果有bean实现了commandlinerunner接口并重写了run方法,则遍历执行commandlinerunner中的方法
2.2.1 new stopwatch()—创建计时器
stopwatch是springframework.util中提供的一个工具类,在启动过程中使用stopwatch是为了记录启动花费的时间。
2.2.2 configureheadlessproperty()—配置headless模式
headless模式是在环境缺少显示器等设备情况下的一种配置,和我们启动流程并无太多关系
2.2.3 springapplicationrunlistener.start()—获取监听器,启动监听
监听器可以用来监听springapplication启动过程中的各个阶段。默认的监听器是eventpublishrunlistener,用户也可以通过实现springapplicationrunlistener接口,实现应用程序对springapplication启动过程的监听。
在resources/meta-inf 下建立 spring.factories 文件,文件中添加 key=value形式,其中 key 为 springapplicationrunlistener 的全路径名,value 为应用程序对该接口的实现类(类需要一个参数类型为 springapplication 和 string 数组的构造函数,用于通过反射创建实例)。
2.2.4 prepareenvironment()—准备环境,创建configurableenvironment对象
在这一步,springapplication会创建spring启动所需的环境,这个环境主要由configurableenviroment对象表示。首先,该对象确认了程序是否需要设置web环境,其次,该对象还确定了程序所需要的参数和读取的配置文件等信息。
此步骤会回调springapplicationrunlistener的environmentprepared()方法,通知监听器环境已经准备好。
2.2.5 printbanner()—打印横幅
这一步骤其实和启动并没有太大关系,只是会向控制台或是日志中输出spring的logo和版本信息。
2.2.6 createapplicationcontext()—创建应用程序上下文并加载bean
在准备好环境之后,接下来要做的就是创建应用程序上下文applicationcontext对象。 applicationcontext是spring ioc的核心组件,它不仅是程序所需bean的容器,还提供了国际化,事件发布等功能。
在创建应用程序上下文的时候,首先会根据之前配置决定上下文的具体类型(annotationconfigapplicationcontext或是annotationconfigservletwebserverapplicationcontext)。 再通过反射实例化到对象。
2.2.7 preparecontext()—准备applicationcontext
虽然已经得到了applicationcontext对象,但此时的对象还只是一个空白对象,需要准备和处理后,applicationcontext才能被使用。
在准备过程中主要做了做了几件事:
为applicationcontext设置之前准备好的environment对象。通过对applicationcontext后置处理或是beandefinitionloader等方式往容器中添加一些初始的bean应用默认的初始化器初始化应用程序上下文(责任链模式的应用,多个初始化器形成一个list,应用程序需要被每个初始化器应用一次,每个初始化器有自己的职责)。准备过程中applicationrunlistener发出两个消息,分别是contextprepared和contextloaded
2.2.8 refreshcontext()—刷新上下文
在应用程序上下文准备好后,可以通过刷新应用程序上下文发现bean并加载到容器中。 refreshcontext()会调用applicationcontext.refresh()方法。 abstractapplicationcontext中定义了refresh()方法的基本框架(模板模式的应用)。
2.2.8.1 preparerefresh()—准备刷新
准备刷新的阶段做了初始化和校验的工作。比如初始化启动时间,初始化propertysources(在abstractapplicationcontext中只是一个空方法,留给子类根据需要实现),以及校验环境中是否已经有必要的参数。
2.2.8.2 preparebeanfactory()—准备beanfactory
beanfactory是 spring 框架中容器的底层实现,所有的 bean 都存放在beanfactory中,虽然applicationcontext也实现了beanfactory接口,但是在其内部还是将获取 bean 的相关操作委托给内部的defaultlistablebeanfactory变量,只是applicationcontext帮用户屏蔽了底层的操作,同时提供出一些更符合外部用户使用的接口。
对beanfactory的准备主要是:
添加一些必要组件,比如类加载器,表达式解析器,属性编辑器注册表等。 以及一些后置处理器,比如applicationcontextawareprocessor(xxxaware的接口就是通过后置处理器在bean创建的时候,通过后置处理器设置的)。 此外还有一些特殊的bean,environment,systemproperties和systemenvirnoment。点击查看spring核心之bean生命周期和三级缓存
2.2.8.3 postprocessbeanfactory()—后置处理beanfactory
对于非webservlet环境的applicationcontext而言这个方法是个空方法,但是web环境下的applicationcontext会通过这个方法定制一些后处理动作,比如添加webapplicationcontextservletawareprocessor后置处理器,添加在web环境中可能使用的scope(session和request)。
2.2.8.4 invokebeanfactorypostprocessors()—实例化并调用beanfactorypostprocessor
beanfactorypostprocessor是一种特殊的后置处理器,其操作的对象是针对beanfactory。 此时主要有三个后置处理器,分别是:sharedmetadatareaderfactorycontextinitializer$cachingmetadatareaderfactorypostprocessor , configurationwarningsapplicationcontextinitializer$configurationwarningspostprocessor和configfileapplicationlistener$propertysourceorderingpostprocessor。这三个类名字虽然很长,但是其实是因为内部类的关系,而且我们看名字也能发现类是怎么来的(外部类是xxxinitializer的就说明是初始化器设置的)。
其中第一个类和启动流程有关,因为它会向容器注册configurationclasspostprocessor。
如果beanfactorypostprocessor同时又是beandefinitionregistrypostprocessor,则先进行针对beandefinition注册表的后置处理,目的是为了发现bean。 在最初的三个beanfactoryprocessor后置处理完成后,会从容器中获取beandefinitionregistrypostprocessor类型的后置处理器(这里主要会得到刚才加载的configurationclasspostprocessor实例)。再调用这些beandefinitionregistry的后置处理器,继续向发现并向容器中注册新的bean。
这里主要是通过@configuration注解作为入口发现bean,如果发现的bean中又存在新的@configurationbean,则以此bean为入口再进行发现,直到所有的bean都被发现。
在针对beandefinition注册表的后置处理完成(发现bean的过程)中,如果找到了beanfactorypostprocessor(包括最初的三个beanfatoryprocessor),会进行针对beanfactory的后置处理过程(之前只是进行针对注册表的后置处理,二者的目的还是有区别的)。
注意 bean的发现过程只是向beandefinition注册表注册beandefinition的过程,并没有针对发现的bean进行实例化(少部分需要用到的bean会进行实例化,比如这部分会对beandefinitionregistrypostprocessor类型的bean实例化)。
2.2.8.5 registerbeanpostprocessors()—注册bean后置处理器
上一步是针对beanfactory和beandefinitionregistry的后置处理器,这一步从beanfactory中获取针对普通bean的后置处理器beanfactorypostprocessor放到专门的容器beanpostprocessors中。
2.2.8.6 initmessagesource()—初始化messagesource
messagesource是拥有特殊功能的bean,用来处理国际化相关内容。
2.2.8.7 initapplicationeventmulticaster()—初始化applicationeventmulticaster
applicationeventmulticaster是applicationevent广播器,可以通过这个对象向容器中添加移除listener,也可以通过这个对象发布事件(观察者模式的应用)。
2.2.8.8 onrefresh()—刷新应用程序
发现了所有的bean,并且需要实例化的bean也都被创建好了之后,spring接下去要做的是创建themesource(和主题相关的组件),以及创建webserver(如果是web环境的话)。
2.2.8.9 registerlisteners()—注册监听器
这一步会将初始化得到的applicationlistener方法和容器中获得applicationlistener一起注册到applicationeventmulticaster中,并且如果存在需要早起发布的事件,则发布事件。
2.2.8.10 finishbeanfactoryinitialzation()—初始化容器中的bean
经过之前的步骤,现在容器中必要的组件都已经准备好了,并且所有需要容器管理的bean也都已经被发现注册成beandefinition注册表中。 对于scope是singleton的bean而言,此时已经具备了实例化bean的条件,因此在这一步中,spring会对所有singleton且非lazy-init的bean进行实例化。 主要做法就是获取容器中所有为singletion且非lazyinit的beandefinition,然后通过getbean创建出bean的实例,保存在容器内部。
有一种特殊的情况是针对factorybean,factorybean是一种用来创建bean的特殊bean,在得到factorybean的bean之后,还需要判断是否要创建factorybean负责创建的bean
2.2.8.11 finishrefresh()—完成刷新
在这步主要是一些资源清理以及注册lifecycleprocessor。lifecycleprocessor可以用来在 spring 生命周期的refresh和close时触发回调。 并且发布refresh的消息。
2.2.9 afterrefresh()—留给子类的钩子函数
在application完成刷新后,springapplication给子类留了afterrefresh()的方法作为回调。
2.3 启动完成
启动完成后,stopwatch会记录下本次启动消费的时间。 然后向applicationrunlistener发布started事件,说明已经启动就绪。
2.4 准备运行
启动完成后,正式运行前,springapplication还会执行用户定义的applicationrunner和commandlinerunner两个接口中定义的run()方法。 在执行完成后,向applicationrunlistener发布runing的消息。 至此,启动流程结束。
3 总结
本文旨在对springboot启动流程各个步骤做一次梳理(本文的段落标题就是启动的各个步骤,不同等级的标题也含有方法前后调用的关系),并没有对每行代码做深入分析
另外,在贴一份整理的不错的流程图帮助大家加深印象。
转载于 : https://www.cnblogs.com/insanexs/p/12721306.html
还没有评论,来说两句吧...