lazy init控制加载在Spring中如何实现源码分析

2022-10-07,,,,

一、lazy-init说明

applicationcontext实现的默认行为就是在启动时将所有singleton bean提前进行实例化(也就是依赖注入)。

提前实例化意味着作为初始化过程的一部分,applicationcontext实例会创建并配置所有的singleton bean。

通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天)。

<bean id="testbean" class="com.fhx.testbean">

该bean默认的设置为:

<bean id="testbean" class="com.fhx.testbean" lazy-init="false">

lazy-init="false" 立退加载, 表示spring启动时,立刻进行实例化。

(lazy-init 设置只对scop属性为singleton的bean起作用)

有时候这种默认处理可能并不是你想要的。如果你不想让一个singleton bean在applicationcontext实现在初始化时被提前实例化,那么可以将bean设置为延迟实例化。

, lazy-init="true"> 延迟加载 ,设置为lazy的bean将不会在applicationcontext启动时提前被实例化,而是在第一次向容器通过getbean索取bean时实例化的。

如果一个设置了立即加载的bean1,引用了一个延迟加载的bean2,那么bean1在容器启动时被实例化,而bean2由于被bean1引用,所以也被实例化,这种情况也符合延迟加载的bean在第一次调用时才被实例化的规则。 在容器层次中通过在元素上使用'default-lazy-init'属性来控制延迟初始化也是可能的。如下面的配置:

<beans default-lazy-init="true"><!-- no beans will be eagerly pre-instantiated... --></beans>

一般beans 和 bean 层次配置的默认值都是false;并且bean的优先级>beans的优先级 如果一个bean的scope属性为scope=“pototype“时,即使设置了lazy-init="false",容器启动时不实例化bean,而是调用getbean方法是实例化的;

现在我们通过源码分析一下;

二、lazy-init 属性被设置的地方

并且优先级 bean>beans; 如果想看所有属性被设置的地方请看博文 spring是如何解析xml中的属性到beandefinition中的

//解析bean的属性值
 public abstractbeandefinition parsebeandefinitionattributes(element ele, string beanname, beandefinition containingbean, abstractbeandefinition bd) {
 // 省略
 //如果当前元素没有设置 lazyinit 懒加载;则去 this.defaults.getlazyinit();这个defaults是上一篇分析过的;整个xml文件全局的默认值;
        string lazyinit = ele.getattribute(lazy_init_attribute);
        if (default_value.equals(lazyinit)) {
            lazyinit = this.defaults.getlazyinit();
        }
//省略....
}

三、lazy-init发挥作用的地方

@override
	public void refresh() throws beansexception, illegalstateexception {
	// 忽略..
	// 实例化所有剩余非 lazy-init 为true的单例对象
		finishbeanfactoryinitialization(beanfactory);
	// 忽略..		
	}

最终执行了 beanfactory.preinstantiatesingletons();

	@override
	public void preinstantiatesingletons() throws beansexception {
		if (this.logger.isdebugenabled()) {
			this.logger.debug("pre-instantiating singletons in " + this);
		}
		// iterate over a copy to allow for init methods which in turn register new bean definitions.
		// while this may not be part of the regular factory bootstrap, it does otherwise work fine.
		list<string> beannames = new arraylist<string>(this.beandefinitionnames);
		// 遍历所有bean
		for (string beanname : beannames) {
			rootbeandefinition bd = getmergedlocalbeandefinition(beanname);
			//1.bd的abstract属性是false;<bean abstract="false"> 不能被实例化,它主要作用是被用作被子bean继承属性用的;
			//2.单例对象并且 lazy-init为false
			//满足上面条件才行
			if (!bd.isabstract() && bd.issingleton() && !bd.islazyinit()) {
			/**
			*如果实现了factorybean接口
			*1.先将factorybean的实现类实例化;
			*2.判断是否将factorybean实现类的getobject方法返回的实例对象也实例化;判断依据
			*  2.1如果当前bean实现了smartfactorybean接口,并且iseagerinit()返回true;才会调用工厂类的方法
			*/
				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 {
						iseagerinit = (factory instanceof smartfactorybean &&
								((smartfactorybean<?>) factory).iseagerinit());
					}
					if (iseagerinit) {
						getbean(beanname);
					}
				}
				else {//如果不是factorybean接口之间实例化
					getbean(beanname);
				}
			}
		}
		// 调用所有smartinitializingsingleton类型的实现类的aftersingletonsinstantiated方法;通过名字可以知道它表示 单例对象实例化后需要做的操作
		for (string beanname : beannames) {
			object singletoninstance = getsingleton(beanname);
			if (singletoninstance instanceof smartinitializingsingleton) {
				final smartinitializingsingleton smartsingleton = (smartinitializingsingleton) singletoninstance;
				if (system.getsecuritymanager() != null) {
					accesscontroller.doprivileged(new privilegedaction<object>() {
						@override
						public object run() {
							smartsingleton.aftersingletonsinstantiated();
							return null;
						}
					}, getaccesscontrolcontext());
				}
				else {
					smartsingleton.aftersingletonsinstantiated();
				}
			}
		}
	}

四、问答

1.ioc容器在实例化bean的时候,ioc会主动调用factorybean类型的的getobject方法来为我们生成对象吗?

答: 一般情况下是不会的,一般情况碰到factorybean类型的是调用 getbean(&beanname),但是有一种情况例外,如果这个factorybean还实现了smartinitializingsingleton接口的话,ioc就会帮我们主动调用getbean(beanname)来实例化;

以上就是lazy init控制加载在spring中如何实现源码分析的详细内容,更多关于spring lazy init控制加载的资料请关注其它相关文章!

《lazy init控制加载在Spring中如何实现源码分析.doc》

下载本文的Word格式文档,以方便收藏与打印。