Spring lazy-init 原理分析
本文我说了很多次 spring 容器初始化和bean初始化,容器的初始化有可能包括bean的初始化主要取决于该bean是否是懒加载的,特此说明怕误会 。。。:)
1 package com.test.spring; 2 3 public class coffee { 4 5 public coffee() { 6 system.out.println("正在初始化bean !!!调用无参构造函数"); 7 } 8 9 }
<bean name="coffee" class="com.test.spring.coffee"/>
1 @test 2 public void testlazyinit() { 3 4 system.out.println("开始初始化spring容器 "); 5 // 非懒加载的bean会在容器初始化时进行bean的初始化,后面会拿spring启动时的源码进行分析 6 applicationcontext context = new classpathxmlapplicationcontext("spring-beans.xml"); 7 // 非懒加载的bean 的构造函数会在这个位置打印 8 system.out.println("spring容器初始化完毕"); 9 10 system.out.println("开始从容器中获取bean"); 11 12 coffee coffee = context.getbean("coffee", coffee.class); 13 14 system.out.println("获取完毕 bean :" + coffee); 15 }
<bean name="coffee" class="com.test.spring.coffee" lazy-init="true" />
@test public void testlazyinit() { system.out.println("开始初始化spring容器 "); // 在初始化容器阶段不会对懒加载的bean进行初始化 applicationcontext context = new classpathxmlapplicationcontext("spring-beans.xml"); system.out.println("spring容器初始化完毕"); system.out.println("开始从容器中获取bean"); // 在这一阶段会对懒加载的bean进行初始化 coffee coffee = context.getbean("coffee", coffee.class); system.out.println("获取完毕 bean :" + coffee); }
运行结果如下:
二,原理分析
spring 启动时主要干俩件事 1.初始化容器 2.对bean进行初始化并依赖注入。(懒加载的bean不做第二件)
但是对于大多数bean来说,bean的初始化以及依赖注入就是在容器初始化阶段进行的,只有懒加载的bean是当应用程序第一次进行getbean时进行初始化并依赖注入。下面贴出代码看下
spring 容器初始化代码如下就一行:
applicationcontext context = new classpathxmlapplicationcontext("spring-beans.xml");
public classpathxmlapplicationcontext(string[] configlocations, boolean refresh, applicationcontext parent) throws beansexception { super(parent); setconfiglocations(configlocations); if (refresh) { // spring ioc 启动入口 了解了refresh 就了解了ioc refresh(); } }
spring 初始化入口 refresh(省略了部分根本次无关的代码,望理解,太长了影响阅读体验)
1 public void refresh() throws beansexception, illegalstateexception { 2 synchronized (this.startupshutdownmonitor) { 3 // prepare this context for refreshing. 4 preparerefresh(); 5 6 // prepare the bean factory for use in this context. 7 preparebeanfactory(beanfactory); 8 9 try { 10 // allows post-processing of the bean factory in context subclasses. 11 postprocessbeanfactory(beanfactory); 12 13 // invoke factory processors registered as beans in the context. 14 invokebeanfactorypostprocessors(beanfactory); 15 16 // register bean processors that intercept bean creation. 17 registerbeanpostprocessors(beanfactory); 18 // instantiate all remaining (non-lazy-init) singletons. 19 // 初始化所有非 懒加载的bean!!!! 20 finishbeanfactoryinitialization(beanfactory); 21 22 // last step: publish corresponding event. 23 finishrefresh(); 24 } 25 }
第20行则是跟本次主题有关的,就是说在容器启动的时候 只处理 non-lazy-init bean,懒加载的bean在spring启动阶段根本不做任何处理下面看下源码就明白了
点进去第20行的finishbeanfactoryinitialization(beanfactory)里头有个初始化non-lazy-init bean的函数 preinstantiatesingletons()
具体逻辑如下
1.对beannames 集合遍历获取每个beandefinition
2.判断是否是懒加载的,如果不是则继续处理(non-lazy-init bean 不做处理)
3.判断是否是factorybean 如果不是则进行实例化并依赖注入
public void preinstantiatesingletons() throws beansexception { // 所有beandefinition集合 list<string> beannames = new arraylist<string>(this.beandefinitionnames); // 触发所有非懒加载单例bean的初始化 for (string beanname : beannames) { // 获取bean 定义 rootbeandefinition bd = getmergedlocalbeandefinition(beanname); // 判断是否是懒加载单例bean,如果是单例的并且不是懒加载的则在spring 容器 if (!bd.isabstract() && bd.issingleton() && !bd.islazyinit()) { // 判断是否是factorybean if (isfactorybean(beanname)) { final factorybean<?> factory = (factorybean<?>) getbean(factory_bean_prefix + beanname); boolean iseagerinit; if (system.getsecuritymanager() != null && factory instanceof smartfactorybean) { iseagerinit = accesscontroller.doprivileged(new privilegedaction<boolean>() { @override public boolean run() { return ((smartfactorybean<?>) factory).iseagerinit(); } }, getaccesscontrolcontext()); } }else { // 如果是普通bean则进行初始化依赖注入,此 getbean(beanname)接下来触发的逻辑跟 // context.getbean("beanname") 所触发的逻辑是一样的 getbean(beanname); } } } }
getbean() 方法是实现bean 初始化以及依赖注入的函数
1 @override 2 public object getbean(string name) throws beansexception { 3 return dogetbean(name, null, null, false); 4 }
三,总结
对于被修饰为lazy-init的bean spring初始化阶段不会进行init并且依赖注入,当第一次进行getbean时候进行初始化并依赖注入
对于非懒加载的bean getbean的时候会从缓存里头取 因为容器初始化阶段已经初始化了
// 容器启动初始化 会初始化并依赖注入非懒加载的bean 1 applicationcontext context = new classpathxmlapplicationcontext("spring-beans.xml"); // lazy-init bean会进行第一次初始化并依赖注入 其他的会从缓存里取 2 coffee coffee = context.getbean("coffee", coffee.class);
上一篇: PHP中的多态
下一篇: Python基础之文本格式化