1 lazy-init

lazy-init是延迟初始化的意思。

spring中容器都是尽早的创建和配置所有的单例bean,因此当容器在启动时,就会去配置和创建单例bean。  默认情况下 beans 的lazy-init 是没有配置的,就相当于是:

default-lazy-init="false"

 bean 的 lazy-init 默认继承于 beans 的配置。 也就是说, 不配置任何lazy-init 的情况下: lazy-init = false 

这样做的好处是在程序刚运行时就可以将配置的错误或者环境问题立刻暴露出来。当然,坏处就是启动时,因为要初始化所有的单例bean,系统开销会很大,启动过程比较慢。

如果不想单例bean提前实例化,可以设置lazy-initialized延迟加载,只有在第一次请求的时候采取初始化,而不是在启动容器时初始化。

如果一个非延迟的单例bean依赖了标记了lazy-init的bean,那么这个标记了lazy-init的bean也会在容器启动时被创建(延迟初始化失效)。 
设置为延迟加载的bean一旦注入给不延迟的单例bean,就意味着它并不会被延迟加载了。

可以看到代码中对所有注册的bean,即this.beanDefinitionNames,对于每个bean都会做如下判断,如果成立就会执行依赖注入:

容器的初始化是在AbstractApplicationContext的refresh()方法中执行的,如下代码对lazy-init进行了处理:

  1. finishBeanFactoryInitialization(beanFactory);

跟踪下去可以找到真正的读取lazy-init属性进行懒加载相关处理的地方

  1. if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit())

可以看出,只有单例的bean才有可能在容器初始化的时候就完成依赖注入,当lazy-init属性不配置(默认值)或者配置为false的时候,上述if就会成立,当然这里默认不配置abstract属性,所以它默认也是false。if成立,就会执行getBean从而进行依赖注入,这样在容器初始化的过程中就已经实例化了Bean,当真正的请求bean的时候,其实只是从缓存中读取而已。

而如果lazy-init属性配置为true,那么就会进行懒加载了,这样在容器初始化的过程中不会进行依赖注入,只有当第一个getBean的时候才会实例化Bean。

2 lazy-init & depends-on

    <!-- 移除 boss Bean 的属性注入配置的信息 -->
<bean id="boss" class="com.baobaotao.Boss" lazy-init="true"/> <!-- depends-on 测试 ,去掉 lazy-init配置后,也就是设置为 fasle, 那么 -->
<bean id="man" class="com.baobaotao.Man" depends-on="boss" lazy-init="true"/>

depends-on 是表明一种初始化的先后顺序,它 和 直接 直接的属性依赖(比如 Man 拥有一个 boss 属性)还是不一样的。 但是表现是差不多的。

具体来说, 就上面的例子, 如果 man 是延迟初始化的, 那么 boss 是否延迟初始化的都不要紧。 但是 如果 mans 是立即初始化的,那么 boss 也会立即被要求初始化, 即使 boss 设置了 lazy-init="true"。 如果boss 无法autowire 某些属性,那么容器就会抛出异常, man也就无法再完成初始化了!

为什么会这样呢? 观察源码可见:

AbstractBeanFactory.doGetBean 方法:

                final RootBeanDefinition ex1 = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(ex1, beanName, args);
String[] dependsOn = ex1.getDependsOn();
String[] scopeName;
if(dependsOn != null) {  // 这里开始对 bean 所依赖的其他bean 进行处理
scopeName = dependsOn;
int scope = dependsOn.length; for(int ex2 = ; ex2 < scope; ++ex2) {
String dep = scopeName[ex2];
if(this.isDependent(beanName, dep)) {
throw new BeanCreationException(ex1.getResourceDescription(), beanName, "Circular depends-on relationship between \'" + beanName + "\' and \'" + dep + "\'");
} this.registerDependentBean(dep, beanName);
this.getBean(dep);
}
}

另外, 从异常堆栈中, 可见其中存在getBean 和 doGetBean 方法的反复的相互调用,而这个正是 spring 在处理 depends-on 依赖:

    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:) 这里出现了反复相互调用
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:)

3 lazy-init & Autowired 注解

lazy-init 和 Autowired  其实并没有明确的关系。 autowired 负责注入, 而lazy-init 关系到 初始化。 仅有的一点关系是: autowired 注入的 bean 必须是已经初始化成功了的bean。 换句话说, autowired 就相当于调用了 getBean,那么不管lazy-init如何设置, 被autowire需要的被依赖的那个bean 必须初始化。

如果一个bean 需要autowire 注入 另一个无法的bean,那么但是,这个bean 不要求立即初始化, 那么这个autowire 潜在的错误是不会暴露出来的。 也就是说, 推迟了可能出现的异常。

参考:

http://blog.csdn.net/qq30211478/article/details/77847677?locationNum=4&fps=1

http://blog.csdn.net/u011734144/article/details/72632327?locationNum=8&fps=1  : Spring源码分析之lazy-init属性的配置

lazy-init 有3个选项, true, false, default

spring 之 lazy-init Autowired depends-on的更多相关文章

  1. 死磕Spring之IoC篇 - @Autowired 等注解的实现原理

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  2. Spring Injection with @Resource, @Autowired and @Inject

    August 1st, 2011 by David Kessler Overview I’ve been asked several times to explain the difference b ...

  3. Spring Auto-Wiring Beans with @Autowired annotation

    In last Spring auto-wiring in XML example, it will autowired the matched property of any bean in cur ...

  4. Spring - IoC(9): @Resoure & @Autowired

    @Resource 和 @Autowired 都是用来装配依赖的,它们之间有些异同. @Resoure @Resource 是 JSR-250 规范的注解. @Resource 可以标注在字段.方法上 ...

  5. Spring自动装配----注解装配----Spring自带的@Autowired注解

    Spring自动装配----注解装配----Spring自带的@Autowired注解 父类 package cn.ychx; public interface Person { public voi ...

  6. Spring Boot + Netty 中 @Autowired, @Value 为空解决

    问题描述 使用 Spring Boot + Netty 新建项目时 Handler 中的 @Autowired, @Value 注解的始终为空值 解决方法 @Component // 1. 添加 @C ...

  7. Spring注解@Resource和@Autowired区别对比

    转载:http://www.cnblogs.com/think-in-java/p/5474740.html @Resource和@Autowired都是做bean的注入时使用,其实@Resource ...

  8. Spring 注解 @Resource和@Autowired(转)

    鸣谢:http://my.oschina.net/u/216467/blog/205951 @Resource和@Autowired两者都是做bean的注入使用. 其实@Resource并不是Spri ...

  9. Spring注解 @Resource和@Autowired

    @Resource和@Autowired两者都是做bean的注入使用.其实@Resource并不是Spring的注解,他的包是javax.annotation.Resource 需要导入.但是Spri ...

  10. 使用Spring的JavaConfig 和 @Autowired注解与自动装配

    1 JavaConfig  配置方法 之前我们都是在xml文件中定义bean的,比如: 1 2 3 4 5 6 7 8 <beans xmlns="http://www.springf ...

随机推荐

  1. Azure SQL 数据库仓库Data Warehouse (3) DWU

    <Windows Azure Platform 系列文章目录> 在笔者的上一篇文章中:Azure SQL 数据库仓库Data Warehouse (2) 架构 介绍了SQL DW的工作节点 ...

  2. GetPostBackEventReference加RaisePostBackEvent实现自定义控件中回调传参

    ; //回调函数,回调参数值:eventArgument        public void RaisePostBackEvent(string eventArgument)        {    ...

  3. 通过U盘启动vmware虚拟机

    不能通过虚拟机的USB功能,而是通过硬盘映射功能实现,操作方法如下图. 1.添加硬盘,注意接口类型与启动系统的支持(XPPE不支持scsi,但10pe支持) 2.硬盘类型 3.选择U盘映射 4.按F2 ...

  4. 1119.(重、错)Pre- and Post-order Traversals

    题目大意: 给定一棵树的结点个数n,以及它的前序遍历和后序遍历,输出它的中序遍历: 如果中序遍历不唯一就输出No,且输出其中一个中序即可,如果中序遍历唯一就输出Yes,并输出它的中序 思路:(转载) ...

  5. java设计模式-Observer(2)

    一.模拟AWT事件处理 回顾一下JDK里面按下一个Button,有件事发生,这个东西怎么写: package com.cy.dp.observer.awt; import java.awt.Butto ...

  6. Flume的Sink

    一.Logger Sink 记录指定级别(比如INFO,DEBUG,ERROR等)的日志,通常用于调试 要求,在 --conf(-c )参数指定的目录下有log4j的配置文件 根据设计,logger ...

  7. [UE4]使用C++重写蓝图,SpawnObject根据类型动态创建UObject

    先大量使用蓝图制作项目,后续再用C++把复杂的蓝图重写一遍,用C++代码按照蓝图依葫芦画瓢就可以了,很简单,但需要遵守一些原则: 第一种方法:使用继承 一.创建一个C++类作为蓝图的父类(C++类继承 ...

  8. 判断Service是否已经启动

     /** 查看服务是否开启*/    public static Boolean isServiceRunning(Context context, String serviceName) {     ...

  9. Python的多态、继承与封装

    一.多态 不用知道变量所引用的对象类型,还是能对它进行操作,它会根据对象(或类)的类型不同而表现出不同的行为. def run_twice(animal): animal.run() animal.r ...

  10. AWS之搭建深度学习主机

    B.G 至2017.11 GPU选型:(参考知乎.CSDN) 高性价比的两款:GTX1080ti, Titan X --通常调试算法  i7CPU+32G内存+SSD+2*GPU(单块显存>6G ...