静态代码块、构造方法和被@PostConstruct修饰的方法的执行顺序

本文详细解析了SpringBoot项目中@PostConstruct注解的使用方法及执行顺序,通过实例演示了该注解如何在依赖注入完成后执行初始化操作,揭示了静态代码块、构造方法与@PostConstruct修饰方法之间的执行顺序。

- 在springboot项目中,我们要定义初始化方法一般都是直接标记@PostConstruct,这样更方便很多。

文档上介绍的
@PostConstruct 注释用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化

那么我们就直接来创建一个springboot项目进行测试看看,如下:
在创建好的springboot项目中创建一个类

@Service
public class TestService{

  static {
    System.out.println("静态代码块.................");
  }

  public ScannerSerialService() {
    System.out.println("构造方法...................");
  }

  //进行初始化操作
  @PostConstruct
  public void init(){
    System.out.println("被@PostConstruct修饰的方法...........");
  }
  	
}

直接启动springboot项目,得到的结果如下:
在这里插入图片描述

所以他们三个的执行顺序是:

 1.静态代码块
 2.构造方法
 3.@PostConstruct修饰的方法**
<think>我们要讨论的是@PostConstruct注解修饰方法在Spring框架中是如何被执行的。 首先,@PostConstruct是Java EE规范中的一部分,现在被包含在JSR-250中。Spring作为Java应用框架,也支持这个注解。 该注解用于标注在方法上,表示该方法在依赖注入完成之后,初始化阶段执行。它相当于Spring的InitializingBean接口的afterPropertiesSet()方法,也相当于XML配置中bean的init-method。 在Spring中,@PostConstruct注解的方法执行是通过BeanPostProcessor实现的。具体来说,Spring提供了一个名为`CommonAnnotationBeanPostProcessor`的处理器来处理JSR-250注解,包括@PostConstruct@PreDestroy。 执行源码流程大致如下: 1. 在Spring容器启动时,会创建bean实例,并完成依赖注入。 2. 在bean的初始化阶段,会应用所有的BeanPostProcessor。其中,CommonAnnotationBeanPostProcessor会检测bean中是否有@PostConstruct注解的方法。 3. 如果有,则将这些方法收集起来(在初始化回调之前执行)。 4. 然后,在BeanPostProcessor的postProcessBeforeInitialization方法中,通过反射调用这些方法。 具体源码分析(简化版): 在`CommonAnnotationBeanPostProcessor`中,其父类`InitDestroyAnnotationBeanPostProcessor`定义了初始化注解类型,其中就包括@PostConstruct。 在`InitDestroyAnnotationBeanPostProcessor`中有一个`postProcessBeforeInitialization`方法,该方法会在bean初始化之前被调用,它负责执行生命周期初始化方法代码片段(来自Spring框架): ``` public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 查找bean中的生命周期元数据(包括@PostConstruct方法) LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { // 调用初始化方法 metadata.invokeInitMethods(bean, beanName); } catch (InvocationTargetException ex) { // ... 异常处理 } return bean; } ``` 在`findLifecycleMetadata`方法中,会构建或从缓存中获取该bean类的生命周期元数据,其中就包括标注了@PostConstruct方法。 在`LifecycleMetadata`的`invokeInitMethods`方法中,会遍历所有找到的初始化方法(即@PostConstruct方法),并通过反射调用它们。 注意:@PostConstruct方法在同一个bean中可以有多个,执行顺序方法名的字母顺序执行(但不推荐一个类中有多个@PostConstruct方法)。 总结:@PostConstruct方法是在bean实例化、依赖注入之后,在初始化回调(如InitializingBean的afterPropertiesSet)之前执行,由CommonAnnotationBeanPostProcessor处理。 因此,如果你在代码中使用了@PostConstruct注解,确保Spring容器中注册了处理这个注解的处理器(CommonAnnotationBeanPostProcessor)。在基于注解的配置中(如使用@ComponentScan或@Configuration),Spring会自动注册这些处理器。 示例代码: 假设我们有一个服务类: ``` import javax.annotation.PostConstruct; public class MyService { @PostConstruct public void init() { System.out.println("MyService初始化..."); } } ``` 当Spring容器创建MyService的bean时,在依赖注入完成后,会调用init()方法。 §§相关问题§§: 1. @PostConstruct注解的作用是什么? 2. 在Spring中,@PostConstruct注解的方法是在哪个阶段被调用的? 3. 如果一个类中有多个@PostConstruct方法,它们的执行顺序是怎样的? 4. Spring中处理@PostConstruct注解的BeanPostProcessor是什么?</think>### @PostConstruct修饰方法执行源码分析 在Spring框架中,`@PostConstruct`注解标记的方法执行流程主要涉及以下核心组件(以Spring 5.3.x源码为例): #### 核心源码流程: 1. **入口点:`AbstractAutowireCapableBeanFactory`** ```java // 初始化Bean的方法 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { // ... invokeInitMethods(beanName, wrappedBean, mbd); // 触发初始化方法 // ... } ``` 2. **初始化方法调用链:`CommonAnnotationBeanPostProcessor`** ```java public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor { // 构造函数指定了初始化注解类型 public CommonAnnotationBeanPostProcessor() { setInitAnnotationType(PostConstruct.class); // 关键:绑定@PostConstruct注解 } } ``` 3. **注解扫描执行:`InitDestroyAnnotationBeanPostProcessor`** ```java public Object postProcessBeforeInitialization(Object bean, String beanName) { // 1. 查找Bean中所有@PostConstruct方法 LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass()); try { // 2. 通过反射执行这些方法 metadata.invokeInitMethods(bean, beanName); } catch (Throwable ex) { throw new BeanCreationException(...); } return bean; } ``` 4. **反射执行方法:`LifecycleMetadata.invokeInitMethods()`** ```java public void invokeInitMethods(Object target, String beanName) throws Throwable { // 遍历所有收集到的初始化方法 for (LifecycleElement element : this.initMethods) { // 通过反射调用目标方法 element.invoke(target); } } ``` #### 关键设计: 1. **BeanPostProcessor机制** Spring通过`BeanPostProcessor`接口扩展点处理注解,`CommonAnnotationBeanPostProcessor`是专门处理JSR-250注解的处理器。 2. **方法收集时机** 在Bean实例化后,依赖注入完成前,Spring会通过反射扫描类中所有标记`@PostConstruct`的方法并缓存(`LifecycleMetadata`)。 3. **执行顺序保证** 若存在多个`@PostConstruct`方法执行顺序按以下规则: - 父类方法优先于子类 - 同层级方法方法名字母顺序执行(可通过`@Order`调整) #### 示例代码: ```java import javax.annotation.PostConstruct; public class DatabaseService { @PostConstruct public void initConnection() { System.out.println("Database connection initialized!"); } @PostConstruct @Order(1) // 控制同层级执行顺序 public void validateConfig() { System.out.println("Configuration validated!"); } } ``` #### 注意事项: 1. 方法必须满足以下条件: - 返回类型为`void` - 无参数 - 非静态方法 - 可抛出检查异常 2. 执行阶段位于: ```mermaid graph LR A[Bean实例化] --> B[依赖注入] B --> C[执行@PostConstruct方法] C --> D[InitializingBean.afterPropertiesSet] D --> E[自定义init-method] ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值