Spring Bean初始化及@PostConstruc执行顺序

目录

1. Bean初始化执行顺序

1.1 构造函数(Constructor)

1.2 依赖注入(Dependency Injection, DI)

1.3 BeanPostProcessor.postProcessBeforeInitialization

1.4 @PostConstruct 方法

1.5 InitializingBean.afterPropertiesSet()

1.6 自定义 initMethod

1.7 BeanPostProcessor.postProcessAfterInitialization

1.8 完整执行顺序总结

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.1 构造函数(Constructor)

  • 首先调用 Bean 的构造函数创建实例。

  • 此时依赖注入尚未完成,Bean 的属性还是默认值(如 null 或基本类型的默认值)。

1.2 依赖注入(Dependency Injection, DI)

  • Spring 通过反射或 setter 方法注入依赖的属性(@Autowired@Resource@Value 等)。

1.3 BeanPostProcessor.postProcessBeforeInitialization

  • 在所有初始化回调(@PostConstructInitializingBeaninitMethod)之前执行。

  • 例如,@PostConstruct 的处理就是通过 CommonAnnotationBeanPostProcessor 在这个阶段触发的。

1.4 @PostConstruct 方法

  • 由 CommonAnnotationBeanPostProcessor 调用,在依赖注入完成后执行。

  • 通常用于自定义初始化逻辑。

1.5 InitializingBean.afterPropertiesSet()

  • 如果 Bean 实现了 InitializingBean 接口,Spring 会调用 afterPropertiesSet() 方法。

1.6 自定义 initMethod

  • 如果 Bean 在配置中指定了 initMethod(如 @Bean(initMethod = "init") 或 XML 配置的 init-method),Spring 会调用它。

1.7 BeanPostProcessor.postProcessAfterInitialization

  • 在所有初始化回调完成后执行。

  • 例如,AOP 代理的创建通常发生在这个阶段。

1.8 完整执行顺序总结

  1. 构造函数(Bean 实例化)

  2. 依赖注入(属性赋值)

  3. BeanPostProcessor.postProcessBeforeInitialization

  4. @PostConstruct 方法

  5. InitializingBean.afterPropertiesSet()

  6. 自定义 initMethod

  7. BeanPostProcessor.postProcessAfterInitialization

public class ExampleBean implements InitializingBean, BeanPostProcessor {

    public ExampleBean() {
        System.out.println("1. 构造函数");
    }

    @Autowired
    public void setDependency() {
        System.out.println("2. 依赖注入");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("3. @PostConstruct方法");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("4. InitializingBean的afterPropertiesSet()");
    }

    public void init() {
        System.out.println("5. 自定义init方法");
    }

    public void destroy() {
        System.out.println("8. destroy方法");
    }


    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("6. postProcessBeforeInitialization方法");
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("7. postProcessAfterInitialization方法");
        return o;
    }
}





@Configuration
public class AppConfig {
    @Bean(initMethod = "init", destroyMethod = "destroy")
    public ExampleBean getExampleBean() {
        return new ExampleBean();
    }
}


输出:
1. 构造函数
2. 依赖注入
3. @PostConstruct方法
4. InitializingBean的afterPropertiesSet()
5. 自定义init方法
6. postProcessBeforeInitialization方法
7. postProcessAfterInitialization方法

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(显式赋值和初始化块先执行,构造器最后执行)。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值