类加载时,各种初始化方法的执行顺序

引言

        现在要研究的问题是关于Spring框架中各种初始化方法的执行顺序。常见的几种方法,比如static final和final static的区别,构造方法,@Autowired,@PostConstruct,afterPropertiesSet(需要实现InitializingBean接口),还有init-method配置,或者通过@Bean的initMethod属性指定的初始化方法。这些方法的执行顺序是怎样的呢?

        首先,回忆一下Spring bean的生命周期。当容器启动时,Spring会实例化bean,然后进行依赖注入,接着执行一些初始化方法,最后bean就可以被使用了。而销毁的时候也有相应的方法,比如@PreDestroy,DisposableBean的destroy方法,或者destroy-method配置。

        但这里的问题主要集中在初始化阶段的各个方法的执行顺序。那具体来说,当一个bean被创建时,这些方法的执行顺序是怎样的呢?

        首先,构造方法(Constructor)应该是最先被调用的,因为对象实例化的时候首先要调用构造方法。构造方法执行完毕后,Spring会进行依赖注入,这时候@Autowired注解的字段或方法会被处理。所以构造方法之后是@Autowired的处理。

        接下来,可能涉及到@PostConstruct注解的方法,还有InitializingBean接口的afterPropertiesSet方法,以及通过init-method配置的方法。那这三个的顺序是什么呢?

        根据之前学过的知识,@PostConstruct注解的方法会在依赖注入完成后被调用,也就是在构造方法和@Autowired之后执行。而实现了InitializingBean接口的afterPropertiesSet方法会在@PostConstruct之后执行吗?然后才是init-method指定的方法?

或者有没有可能它们的顺序是:@PostConstruct → afterPropertiesSet → init-method?

Spring的官方文档中提到,初始化方法的执行顺序是:

1. @PostConstruct 注解的方法

2. InitializingBean的afterPropertiesSet()

3. 自定义的init-method方法

那这样的话,这三种初始化方法的顺序就是这样的。例如,如果一个bean同时有这三种方法,它们的执行顺序应该是先执行@PostConstruct方法,然后执行afterPropertiesSet,最后执行init-method指定的方法。

        接下来,可以看static final和final static的区别,实际上,在Java中,static final和final static是等价的,它们的顺序不影响变量的声明,只是风格上的差异。所以这可能是一个干扰信息,和初始化顺序无关。构造方法自然是第一步,因为对象必须先实例化。然后是依赖注入,也就是@Autowired的处理,这可能是在构造方法之后,但如果是通过构造方法注入的话,@Autowired可能会在构造方法上使用,这时候构造方法的参数由Spring注入。这时候,构造方法的执行可能是在依赖注入的过程中进行的。例如,如果使用构造器注入,那么构造方法会被Spring调用,并传入所需的依赖项。此时,@Autowired可能标注在构造方法上,不过从Spring 4.3开始,如果类只有一个构造方法,那么不需要显式添加@Autowired注解,Spring会自动使用该构造方法。如果有多个构造方法,则需要指定哪一个用@Autowired。

        接下来,当依赖注入完成后,即所有@Autowired的字段或方法都被处理之后,初始化方法开始执行。这时候,首先执行的是@PostConstruct注解的方法,然后是InitializingBean的afterPropertiesSet()方法,最后是init-method指定的方法。

所以,综合起来,整个顺序应该是:

1. 构造方法(Constructor)

2. @Autowired 注入依赖

3. @PostConstruct 注解的方法

4. afterPropertiesSet() (实现了InitializingBean接口)

5. init-method 指定的方法(通过XML配置或者@Bean的initMethod属性)

不过,需要注意的是,构造方法和@Autowired的顺序可能因注入方式的不同而有所变化。例如,如果是构造器注入,那么构造方法是在实例化的时候调用的,此时参数由Spring注入,这时候@Autowired(如果用在构造方法上)是在构造方法执行的时候处理的。而如果是字段注入或者setter方法注入,那么构造方法执行完毕后,Spring再进行依赖注入。

但不管怎样,@PostConstruct、afterPropertiesSet、init-method这三个初始化方法的执行顺序是确定的,即按照上述顺序执行。

为了验证这个顺序,可以举一个例子,以下涉及了java中各种初始化方法的执行顺序,我们创建一个springboot测试项目来观察加载顺序。

1.创建application.yml

server:
  port: 8080

2.创建Application.java启动类

package com.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication 
public class Application {
	public static void main(String[] args) throws Exception {
         SpringApplication.run(Application.class, args);
     }

}

3.创建SomeDependency.java(用于测试@Autowired)

package com.boot.util;

import org.springframework.stereotype.Component;

@Component
public class SomeDependency {
    public void check() {
        System.out.println("SomeDependency 已注入成功!");
    }
}

4.创建AppConfig.java(用于测试@Bean)

package com.boot.util;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;

@Configuration
@ComponentScan(basePackages = "com.boot.util")  // 确保扫描到SomeDependency
public class AppConfig {
    @Bean(initMethod = "initMethod")
    public MyBean myBean() {
        return new MyBean();
    }
}

5.创建测试类MyBean.java

package com.boot.util;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;

public class MyBean implements InitializingBean {

    // ---------------------
    // 静态字段初始化(类加载时执行)
    // ---------------------
    public static final String STATIC_FINAL_FIELD = "Static Final Field";
    public static String staticField = (STATIC_FINAL_FIELD=="" ? "Static Final 未加载":"Static Final 已加载") +"\nstatic已加载";

    static {
        System.out.println("静态块初始化: staticField = " + staticField);
    }

    // ---------------------
    // 实例字段和依赖注入
    // ---------------------
    @Autowired
    private SomeDependency dependency;

    public MyBean() {
        System.out.println("构造方法调用");
        try{
            dependency.check();  // 验证依赖是否注入
        }catch (Throwable t){
            System.out.println("SomeDependency 还未注入");
        }
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("@PostConstruct方法调用");
        dependency.check();  // 验证依赖是否注入
    }

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

    }

    public void initMethod() {
        System.out.println("自定义init-method调用");
    }
}

6.启动项目,查看控制台输出的结果

7.结论

以下按照加载顺序排列:

  1. static final 或 final static
  2. static
  3. static静态块
  4. 构造方法
  5. @Autowired
  6. @postConstruct
  7. afterpropertiesset()方法,需要实现initializingbean
  8. intmethod方法,@Bean(initMethod = "init") ,等价于 init-method,<bean />配置 
    <bean id="myBean" class="com.boot.util.Mybean" init-method="createPool" />

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值