开发者

Spring Bean初始化及@PostConstruc执行顺序示例详解

目录
  • 1. Bean初始化执行顺序
  • 2. 成员变量初始化顺序
    • 2.1 普通Java类(非Spring环境)
      • (1) 默认初始化(即初始分配内存)
      • (2) 显式初始化
      • (3) 编程客栈构造器初始化
      • (4)完整顺序
    • 2.2 Spring管理的Bean(依赖注入场景)
      • (1) 普通成员变量
      • (2) 依赖注入的成员变量
      • (3) 生命周期回调的影响
      • (4)关键区别总结
    • 2.3 final成员变量
      • 2.4 常见面试问题

      1. Bean初始化执行顺序

      1. 构造函数 - 首先调用Bean的构造函数

      2. 依赖注入 - 完成所有依赖项的注入(@Autowired等)

      3. @PostConstruct方法 - 执行带有@PostConstruct注解的方法

      4. InitializingBean的afterPropertiesSet() - 如果Bean实现了InitializingBeanhttp://www.devze.com接口

      5. 自定义init方法 - 执行通过@Bean(initMethod="...")或XML配置中init-method指定的方法

      @Component
      public class ExampleBean implements InitializingBean {
          public ExampleBean() {
              System.out.println("1. 构造函数");
          }
          @Autowired
          public void setDependency(SomeDependency dep) {
         js     System.out.println("2. 依赖注入");
          }
          @PostConstruct
          public void postConstruct() {
              System.out.println("3. @PostksydNXmRConstruct方法");
          }
          @Override
          public void afterPropertiesSet() {
              System.out.println("4. InitializingBean的afterPropertiesSet()");
          }
          @Bean(initMethod = "customInit")
          public void customInit() {
              System.out.println("5. 自定义init方法");
          }
      }

      2. 成员变量初始化顺序

      在Java中,类的成员变量(非静态成员变量)的初始化时机取决于其定义方式(直接赋值、构造器赋值、初始化块等)以及是否涉及依赖注入(如Spring框架)。

      2.1 普通Java类(非Spring环境)

      成员变量的初始化顺序和时机如下:

      (1) 默认初始化(即初始分配内存)

      • 时机:对象实例化时(new关键字调用构造器之前)。

      • 规则:所有成员变量先被赋予默认值(int0booleanfalse,引用类型→null等)。

      (2) 显式初始化

      • 时机:紧随默认初始化之后,按代码中的声明顺序执行。

      • 方式

        • 直接赋值:

      public class MyClass {
          private int a = 10;          // 显式赋值
          private String s = "hello";  // 显式赋值
      }
      • 初始化块(代码块):
      public class MyClass {
          private int x;
          {
              x = 20; // 初始化块赋值
          }
      }

      (3) 构造器初始化

      • 时机:在显式初始化之后,构造器最后执行。

      • 特点:构造器中的赋值会覆盖之前的默认值或显式赋值。

      public class MyClass {
          private int value;
          public MyClass() {
              this.value = 30; // 构造器赋值
          }
      }

      (4)完整顺序

      默认值 → 显式赋值/初始化块 → 构造器赋值

      2.2 Spring管理的Bean(依赖注入场景)

      在Spring中,成员变量的初始化分为依赖注入普通成员变量初始化两部分:

      (1) 普通成员变量

      • 初始化规则与普通Java类一致(默认值 → 显式赋值 → 构造器)。

      • 示例

      @Component
      public class MyBean {
          private int count = 100;  // 显式赋值(Spring无关)
          public MyBean() {
              this.count = 200;     // 构造器覆盖
          }
      }

      (2) 依赖注入的成员变量

      • 时机:在Bean实例化后,由Spring容器通过反射或Setter方法注入。

        • 字段注入(@Autowired):

          在构造器和显式赋值之后,通过反射直接注入。

          @Component
          public class MyBean {
              @Autowired
              private Dependency dependency; // Spring在对象构造后注入
          }
        • 构造器注入

          在实例化时通过构造器参数注入(等同于普通Java的构造器赋值)。

          @Component
          public class MyBean {
              private final Dependency dependency;
              public MyBean(Dependency dependency) {
                  this.dependency = dependency; // 构造时注入
              }
          }

      (3) 生命周期回调的影响

      • @PostConstruct方法会在依赖注入完成后执行,此时所有成员变量(包括注入的依赖)已就绪:

        @Component
        public class MyBean {
            @Autowired
            private Dependency dependency;
            @PostConstruct
            public void init() {
                System.out.println(dependency); // 依赖已注入
            }
        }

      (4)关键区别总结

      场景成员变量初始化时机
      普通Java类默认值 → 显式赋值/初始化块 → 构造器赋值
      Spring Bean(字段注入)默认值 → 显式赋值 → 构造器 → 依赖注入 → @PostConstruct
      Spring Bean(构造器注入)与普通Java类相同,依赖通过构造器参数传入

      2.3 final成员变量

      • 必须声明时、初始化块或构造器中赋值,否则编译错误。

      public class MyClass {
          private final int x = 10;  // 声明时赋值
          private final int y;
          { y = 20; }  // 初始化块赋值
          private final int z;
          public MyClass() {
              z = 30;  // 构造器赋值
          }
      }

      2.4 常见面试问题

      Q1: 为什么构造器里的赋值能覆盖显式赋值?

      因为构造器是最后执行的,可以修改之前的值。

      Q2: 以下代码的输出是什么?

      public class Test {
          private int x = 10;
          { x = 20; }
          public Test() {
              System.out.println(x);
              x = 30;
          }
          public static void main(String[] args) {
              new Test(); // 输出?
          }
      }
      --
      答案:20(显式赋值和初始化块先执行,构造器编程客栈最后执行)。

      到此这篇关于Spring Bean初始化及@PostConstruc执行顺序的文章就介绍到这了,更多相关Spring Bean初始化内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜