spring 之 lazy-init Autowired depends-on
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进行了处理:
- finishBeanFactoryInitialization(beanFactory);
跟踪下去可以找到真正的读取lazy-init属性进行懒加载相关处理的地方
- 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的更多相关文章
- 死磕Spring之IoC篇 - @Autowired 等注解的实现原理
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 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 ...
- 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 ...
- Spring - IoC(9): @Resoure & @Autowired
@Resource 和 @Autowired 都是用来装配依赖的,它们之间有些异同. @Resoure @Resource 是 JSR-250 规范的注解. @Resource 可以标注在字段.方法上 ...
- Spring自动装配----注解装配----Spring自带的@Autowired注解
Spring自动装配----注解装配----Spring自带的@Autowired注解 父类 package cn.ychx; public interface Person { public voi ...
- Spring Boot + Netty 中 @Autowired, @Value 为空解决
问题描述 使用 Spring Boot + Netty 新建项目时 Handler 中的 @Autowired, @Value 注解的始终为空值 解决方法 @Component // 1. 添加 @C ...
- Spring注解@Resource和@Autowired区别对比
转载:http://www.cnblogs.com/think-in-java/p/5474740.html @Resource和@Autowired都是做bean的注入时使用,其实@Resource ...
- Spring 注解 @Resource和@Autowired(转)
鸣谢:http://my.oschina.net/u/216467/blog/205951 @Resource和@Autowired两者都是做bean的注入使用. 其实@Resource并不是Spri ...
- Spring注解 @Resource和@Autowired
@Resource和@Autowired两者都是做bean的注入使用.其实@Resource并不是Spring的注解,他的包是javax.annotation.Resource 需要导入.但是Spri ...
- 使用Spring的JavaConfig 和 @Autowired注解与自动装配
1 JavaConfig 配置方法 之前我们都是在xml文件中定义bean的,比如: 1 2 3 4 5 6 7 8 <beans xmlns="http://www.springf ...
随机推荐
- Windows右键菜单中新建项目添加与删除
一种是如 txt 类型: HKEY_CLASSES_ROOT\.txt\ShellNew 项下空字符串值:NullFile 另一种如MsOffice类型: HKEY_CLASSES_ROOT\.xl ...
- CentOS 7.4 初次手记:第三章 CentOS基础了解
第三章 CentOS基础了解... 36 第一节 语言编码.终端... 36 I 查看语言编码... 36 II Tty?.pts/?. 36 第二节 bash/sh command. 38 I 查找 ...
- js中的 Table 对象
Table 对象Table 对象代表一个 HTML 表格.在 HTML 文档中 <table> 标签每出现一次,一个 Table 对象就会被创建. Table 对象集合cells[] ...
- 使用RetionalRose根据现有的java工程逆向生成类图
1.进入RetionalRose选择J2EE模板 2.在菜单栏选择tools->java/j2EE->reverse engineer 3.编辑路径Edit CLASSPATH选择要生成类 ...
- 配置文件elasticsearch.yml详解
在es根目录下的config目录中有elasticsearch.yml配置文件,es加载使用的yml格式配置 17行:cluster.name: 自定义集群名称(强烈推荐默认名称elasticsear ...
- 服务链路追踪(Spring Cloud Sleuth)
sleuth:英 [slu:θ] 美 [sluθ] n.足迹,警犬,侦探vi.做侦探 微服务架构是一个分布式架构,它按业务划分服务单元,一个分布式系统往往有很多个服务单元.由于服务单元数量众多,业务的 ...
- 解决hash冲突的三个方法(转)
https://www.cnblogs.com/wuchaodzxx/p/7396599.html 目录 开放定址法 线性探测再散列 二次探测再散列 伪随机探测再散列 再哈希法 链地址法 建立公共溢出 ...
- Tomcat7启动分析(三)Digester的使用(转载)
原文 http://tyrion.iteye.com/blog/1912290 前一篇文章里最后看到Bootstrap的main方法最后会调用org.apache.catalina.startup.C ...
- python urlib2报错gaierror: [Errno 11004] getaddrinfo failed
gaierror : get address info error,获取网络地址信息错误. url不正确,代理信息配置不正确都会报这个错误. 摘自https://blog.csdn.net/qq_19 ...
- 知识点:Navicet Mysql数据库电脑本地备份
Navicet Mysql数据库电脑本地备份 1.打开navicat客户端,连上mysql后,双击左边你想要备份的数据库.点击“计划”,再点击“新建批处理作业”. 2.双击上面的可用任务,它就 ...