springboot---成员初始化顺序
如果我们的类有如下成员变量:
@Component
public class A {@Autowiredpublic B b; // B is a beanpublic static C c; // C is also a beanpublic static int count;public float version;public A() {System.out.println("This is A constructor.");}@Autowiredpublic A(C c) {A.c = c;System.out.println("This is A constructor with c argument.");}@PostConstructpublic void init() {count = 5;System.out.println("This is A post construct.");}
}
下面的结论可以通过在构造函数里打断点Debug来观察。
首先初始化的是static成员变量, 此处的count采用默认值0。
然后初始化的是非static成员变量,此处的version采用默认值0.0。
然后Spring在实例化A时选择的构造函数的原则是:如果有构造函数被@Autowired所修饰,则采用该构造函数(注意,@Autowired(required = true)只能修饰一个构造函数),否则采用默认的无参构造函数。此处采用的构造函数为
@Autowired
public A(C c) {this.c = c;System.out.println("This is A constructor with c argument.");
}
注意执行完该构造函数后,此时的成员变量B并没有被注入,值还是null。
Spring容器选择合适的Bean注入b。
执行被@PostConstruct修饰的init()函数。
总之,在上面这个例子中,各成员变量的执行顺序为:“static 成员变量 ”–> “非static成员变量” --> “被@Autowired修饰的构造函数” --> “被@Autowired修饰的成员变量b” --> “被@PostConstruct修饰的init()函数”。
有时我们想要对静态成员进行依赖注入(通常是Field dependency injection,即直接在成员上加@Autowired,此种做法不推荐),直接在静态成员上加@Autowired是无效的(其值总为null),这是因为静态成员变量是类的属性,不属于任何对象,而Spring实现Field dependency injection 是要依靠基于实例的reflection(反射)进行的。在这个例子中,Spring通过反射生成bean a, 并且发现a使用了bean b(此时bean b已经生成并被注册到Spring容器中),再次利用反射生成setter方法并将b set进a,这样就实现了Field dependency injection。通过上述过程我们可以知道static成员由于不属于任何实例,所以无法实现这样的依赖注入,但是我们可以通过Constructor dependency injection(构造函数依赖注入)来实现。以上面的例子为例,Spring在生成bean a(调用A的构造函数)时,由于A的构造函数带有参数c,Spring将在容器里寻找是否有符合c类型的bean,找到后将bean c赋值给构造函数的参数c,然后当执行到A.c = c时成员变量c就被“注入”成功了。
如果我们希望某个Bean不要在Spring容器启动时初始化(这样可以加快应用的启动速度),而是在用到时才实例化,可以用@Lazy这个注解。将这个注解加在@Bean、@Component、@Service、@Configuration等注解上时,这些注解所修饰的Bean将在第一次引用时才实例化;如果在@Autowired上也同时加上这个注解,则该Bean将在第一次使用时实例化。我们再举个简单的例子:
在@Component等注解上加@Lazy
@Lazy
@Component
public class LazyBean {public LazyBean() {System.out.println("This is LazyBean constructor.");}
}
在UseBean里通过@Autowired注入LazyBean,不加@Lazy:
@Component
public class UseBean {@Autowiredprivate LazyBean lazyBean;public UseBean () {}
}
当应用启动时,Spring要去扫描这些被@Component等注解修饰的类,立即将他们实例化并注册到容器中,但是由于LazyBean 类被@Lazy修饰,Spring会跳过这个Bean的实例化。当生成UseBean后(即Spring完成对UseBean的构造函数的调用后),由于UseBean引用了LazyBean,这个时候Spring才将LazyBean实例化。因此,以上Bean的初始化顺序永远是先初始化UseBean,当执行到@Autowired private LazyBean lazyBean;时才实例化lazyBean。
在@Component等注解和@Autowired上都加@Lazy
@Getter@Componentpublic class UseBean {@Lazy@Autowiredprivate LazyBean lazyBean;public UseBean () {}@PostConstructpublic void init() {System.out.println(this.getLazyBean());}}
这种情况下即使执行到@Autowired private LazyBean lazyBean;时也没有真正实例化LazyBean ,只有在真正使用lazyBean时,即上述代码中的this.getLazyBean()时才开始调用LazyBean 的构造函数来实例化。
springboot---成员初始化顺序相关推荐
- C#中成员初始化顺序
C#中成员初始化顺序 http://blog.csdn.net/huangcailian/article/details/25958967 一.成员初始化整体顺序 1.成员赋值初始化先于构造函数: 2 ...
- java类成员初始化_简单了解Java类成员初始化顺序
这篇文章主要介绍了简单了解Java类成员初始化顺序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 类中包含7中成员: 1.静态变量 static 2 ...
- 【转载】c#类的成员初始化顺序
作者:彭白洋 创建于:2009-01-15 出处:http://www.cnblogs.com/siceblue/archive/2009/01/15/1376430.html 收录于:2013-0 ...
- java成员初始化顺序_Java成员初始化顺序
1. 初始化顺序 在类的内部,变量定义的先后顺序决定了初始化的顺序.即使变量散布于方法定义之间,他们仍会在任何方法(包括构造器)被调用之前初始化. 2. 静态成员初始化顺序 1⃣️初始化类的静态成员或 ...
- Kotlin类成员初始化顺序
Kotlin实例初始化时,构造函数.成员变量.init块等的初始化顺序必须弄清楚,否则容易出bug: Example: open class Parent {private val a = print ...
- Java类的各种成员初始化顺序
初始化规则 1.父类[静态成员]和[静态代码块],按在代码中出现的顺序依次执行. 2.子类[静态成员]和[静态代码块],按在代码中出现的顺序依次执行. 3.父类的[普通成员变量被普通成员方法赋值]和[ ...
- 类成员初始化顺序php,PHP-php类成员变量初始化的问题?
PHP类中,若要初始化成员属性,那么成员属性的初始值必须是一个常数,如果不是常数(如变量),则会报错,所以,如果你要初始化就只能是在构造函数里进行初始化,不过你可以写一个方法,这样就可以在构造函数里批 ...
- lt;转载自刘佳ID:freedom0203和waretgt; C++中成员初始化列表的使用
刘佳: C++在类的构造函数中,可以两种方式初始化成员数据(data member). 1,在构造函数的实现中,初始类的成员数据.诸如: class point { private: int x,y ...
- php键顺序初始化,Java类中各成员初始化的顺序
了解Java中类各个成员的初始化顺序是非常重要的,这样你可以对类有全局的认识.不说太多,直接看下面的例子 class Father { static{ System. out.println(&quo ...
- C++成员变量的初始化顺序问题
C++成员变量的初始化顺序问题 由于面试题中,考官出了一道简单的程序输出结果值的题:如下, [cpp] view plain copy print? class A { private: int n ...
最新文章
- C++ 随机函数----谈rand() 和 srand() 体会
- php 修改文件的权限_php怎么修改文件的权限?
- 1022 Digital Library (30 分) 【难度: 中 / 知识点: 哈希表】
- 常见JSP中文乱码例子及其解决方法
- ByteBuf主要继承关系图
- Qt Quick QMl学习笔记 之图片浏览器
- 编译安装http启动问题
- 博文视点读书节第九日丨大咖书单加倍放送!
- 对股票进行可视化分析
- windowsxp主题包教大家如何制作windows7主题包
- 使用jemeter进行接口压力测试
- python QQ自动添加好友
- 关于librdkafka编译错误问题解决
- 解决Windows照片查看器加载慢和颜色问题
- Image Pro Plus6进行荧光分析与荧光照片合成学习笔记
- 云效首发应用交付和项目协作新品,助力企业DevOps到BizDevOps
- 给view添加单边阴影
- 对视频声音,音频进行音量标准化和响度均化,归一化的标准,原理以及具体操作
- springboot项目有哪几种运行方式
- qduoj 生化危机ycb老师的电脑中毒了(邻接表)
热门文章
- 编译Android版本TensorFlow
- MFC中绘制高亮的图标 VC图标填充半透明色
- 操作系统锁的实现方法有哪几种_「从入门到放弃-Java」并发编程-锁-synchronized...
- oracle 同义词_【干货7】Oracle知识关键代码摘要
- 5错误怎么办_“选择不对,一生白费”:如果选错了,该怎么办?记住这两句话...
- linux命令 重定向%3e,linux输出信息调试信息重定向
- Java生鲜电商平台-统一异常处理及架构实战
- sourcetree,创建工作流报错:Fatal: Not a gitflow-enabled repo yet. Please run 'git flow init' first.-》解决办法...
- [BZOJ]3173: [Tjoi2013]最长上升子序列
- js实现替换指定字符后面的内容(包括指定字符)