如果我们的类有如下成员变量:

@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---成员初始化顺序相关推荐

  1. C#中成员初始化顺序

    C#中成员初始化顺序 http://blog.csdn.net/huangcailian/article/details/25958967 一.成员初始化整体顺序 1.成员赋值初始化先于构造函数: 2 ...

  2. java类成员初始化_简单了解Java类成员初始化顺序

    这篇文章主要介绍了简单了解Java类成员初始化顺序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 类中包含7中成员: 1.静态变量 static 2 ...

  3. 【转载】c#类的成员初始化顺序

    作者:彭白洋 创建于:2009-01-15 出处:http://www.cnblogs.com/siceblue/archive/2009/01/15/1376430.html  收录于:2013-0 ...

  4. java成员初始化顺序_Java成员初始化顺序

    1. 初始化顺序 在类的内部,变量定义的先后顺序决定了初始化的顺序.即使变量散布于方法定义之间,他们仍会在任何方法(包括构造器)被调用之前初始化. 2. 静态成员初始化顺序 1⃣️初始化类的静态成员或 ...

  5. Kotlin类成员初始化顺序

    Kotlin实例初始化时,构造函数.成员变量.init块等的初始化顺序必须弄清楚,否则容易出bug: Example: open class Parent {private val a = print ...

  6. Java类的各种成员初始化顺序

    初始化规则 1.父类[静态成员]和[静态代码块],按在代码中出现的顺序依次执行. 2.子类[静态成员]和[静态代码块],按在代码中出现的顺序依次执行. 3.父类的[普通成员变量被普通成员方法赋值]和[ ...

  7. 类成员初始化顺序php,PHP-php类成员变量初始化的问题?

    PHP类中,若要初始化成员属性,那么成员属性的初始值必须是一个常数,如果不是常数(如变量),则会报错,所以,如果你要初始化就只能是在构造函数里进行初始化,不过你可以写一个方法,这样就可以在构造函数里批 ...

  8. lt;转载自刘佳ID:freedom0203和waretgt; C++中成员初始化列表的使用

    刘佳: C++在类的构造函数中,可以两种方式初始化成员数据(data member). 1,在构造函数的实现中,初始类的成员数据.诸如: class point { private:  int x,y ...

  9. php键顺序初始化,Java类中各成员初始化的顺序

    了解Java中类各个成员的初始化顺序是非常重要的,这样你可以对类有全局的认识.不说太多,直接看下面的例子 class Father { static{ System. out.println(&quo ...

  10. C++成员变量的初始化顺序问题

    C++成员变量的初始化顺序问题 由于面试题中,考官出了一道简单的程序输出结果值的题:如下, [cpp] view plain copy  print? class A { private: int n ...

最新文章

  1. C++ 随机函数----谈rand() 和 srand() 体会
  2. php 修改文件的权限_php怎么修改文件的权限?
  3. 1022 Digital Library (30 分) 【难度: 中 / 知识点: 哈希表】
  4. 常见JSP中文乱码例子及其解决方法
  5. ByteBuf主要继承关系图
  6. Qt Quick QMl学习笔记 之图片浏览器
  7. 编译安装http启动问题
  8. 博文视点读书节第九日丨大咖书单加倍放送!
  9. 对股票进行可视化分析
  10. windowsxp主题包教大家如何制作windows7主题包
  11. 使用jemeter进行接口压力测试
  12. python QQ自动添加好友
  13. 关于librdkafka编译错误问题解决
  14. 解决Windows照片查看器加载慢和颜色问题
  15. Image Pro Plus6进行荧光分析与荧光照片合成学习笔记
  16. 云效首发应用交付和项目协作新品,助力企业DevOps到BizDevOps
  17. 给view添加单边阴影
  18. 对视频声音,音频进行音量标准化和响度均化,归一化的标准,原理以及具体操作
  19. springboot项目有哪几种运行方式
  20. qduoj 生化危机ycb老师的电脑中毒了(邻接表)

热门文章

  1. 编译Android版本TensorFlow
  2. MFC中绘制高亮的图标 VC图标填充半透明色
  3. 操作系统锁的实现方法有哪几种_「从入门到放弃-Java」并发编程-锁-synchronized...
  4. oracle 同义词_【干货7】Oracle知识关键代码摘要
  5. 5错误怎么办_“选择不对,一生白费”:如果选错了,该怎么办?记住这两句话...
  6. linux命令 重定向%3e,linux输出信息调试信息重定向
  7. Java生鲜电商平台-统一异常处理及架构实战
  8. sourcetree,创建工作流报错:Fatal: Not a gitflow-enabled repo yet. Please run 'git flow init' first.-》解决办法...
  9. [BZOJ]3173: [Tjoi2013]最长上升子序列
  10. js实现替换指定字符后面的内容(包括指定字符)