文章目录

  • 一、Bean的生命周期
  • 二、Spring初始化Bean几种方式
  • 1、初始化介绍
  • 2、@PostConstruct注解
  • 3、InitializingBean接口
  • 4、@Bean的initMethod属性
  • 5、三种方式执行顺序
  • 6、总结


一、Bean的生命周期

如何记忆 Spring Bean 的生命周期

spring ioc初始化流程 spring 初始化方法_servlet

二、Spring初始化Bean几种方式

1、初始化介绍

执行顺序:Constructor > @PostConstruct > InitializingBean > init-method

  • 实现InitializingBean接口,重写afterPropertiesSet方法
  • <Bean>元素上添加init-method初始化
  • 使用@PostConstruct注解

2、@PostConstruct注解

javaEE5引入了@PostConstruct和@PreDestroy两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作

@PostConstruct是Java自己的注解

@PostConstruct该注解被用来修饰一个非静态的void()方法

@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次

@PostConstruct在构造函数之后执行,init()方法之前执行

假设类UserController有个成员变量UserService被**@Autowired**修饰,那么UserService的注入是在UserController的构造方法之后执行的。如果想在UserController对象生成时候完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入的对象,那么就无法在构造函数中实现(ps:spring启动时初始化异常),例如:

@Component
public class UserController {
  @Autowired
  private UserService userService;
 
  public UserController() {
    // 调用userService的自定义初始化方法,此时userService为null,报错
    userService.userServiceInit();
  }
}

可以使用@PostConstruct注解来完成初始化,@PostConstruct注解的方法将会在UserService注入完成后被自动调用。

@Component
public class UserController {
  @Autowired
  private UserService userService;
 
  public UserController() {
  }
 
  // 初始化方法
  @PostConstruct
  public void init(){
    userService.userServiceInit();
  }
}

**总结:**类初始化调用顺序:构造方法Constructor > @Autowired > @PostConstruct

3、InitializingBean接口

InitializingBean是Spring提供的拓展性接口,InitializingBean接口为bean提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。

除了采用注解完成初始化,也可以通过实现InitializingBean完成类的初始化

@Component
public class UserController {

  public UserController() {
  }
 
  // 初始化方法
  @PostConstruct
  public void init(){
    userService.userServiceInit();
  }
}

比较常见的如SqlSessionFactoryBean,它就是通过实现InitializingBean完成初始化的。

@Override
public void afterPropertiesSet() throws Exception {
 // buildSqlSessionFactory()是完成初始化的核心方法,必须在构造方法调用后执行
 this.sqlSessionFactory = buildSqlSessionFactory(); 
}

4、@Bean的initMethod属性

initMethod属性通过bean标签中的initMethod来配置实例化之后的初始化方法的

@Component
public class UserController {

  public UserController() {
  }
 
  public void init(){
    userService.userServiceInit();
  }
  
  // 初始化指向init()方法
  @Bean(initMethod = "init")
  public UserController test() {
        return new UserController();
    }
}

5、三种方式执行顺序

通过启动日志我们可以看出执行顺序优先级:构造方法 > postConstruct >afterPropertiesSet > init方法

public class MyInitializingBean implements InitializingBean {

    public MyInitializingBean() {
        System.out.println("我是MyInitializingBean构造方法执行...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("我是afterPropertiesSet方法执行...");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("我是postConstruct方法执行...");
    }

    public void init(){
        System.out.println("我是init方法执行...");
    }
}

@Configuration
class config{
    @Bean(initMethod = "init")
    public MyInitializingBean test() {
        return new MyInitializingBean();
    }
}


//==================执行结果===================
/**
我是MyInitializingBean构造方法执行...
我是postConstruct方法执行...
我是afterPropertiesSet方法执行...
我是init方法执行...
*/

6、总结

  • Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。
  • 实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。
  • 如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。