在日常开发时,我们常常需要 在SpringBoot 应用启动时执行某一些逻辑,如下面的场景:
1、获取一些当前环境的配置或变量;
2、连接某些外部系统,读取相关配置和交互;
3、启动初始化多线程(线程池)。
在sprongboot项目启动初始化加载方式为2类:
- ApplicationRunner与CommandLineRunner接口
- Spring Bean初始化的构造方法、PostConstruct、init-method、InitializingBean
ApplicationRunner与CommandLineRunner
如果需要在SpringApplication启动时执行一些特殊的代码,你可以实现ApplicationRunner或CommandLineRunner接口,这两个接口工作方式相同,都只提供单一的run方法,而且该方法仅在SpringApplication.run(…)完成之前调用,更准确的说是在构造SpringApplication实例完成之后调用run()的时候。
- ApplicationRunner
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class ApplicationRunnerInit implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("执行-->ApplicationRunner");
}
}
- CommandLineRunner
package com.mtaite.study.mybatis.init;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(1)
public class CommandLineRunnerInit implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("执行-->CommandLineRunner...");
}
}
Spring Bean初始化的构造方法、PostConstruct、init-method、InitializingBean
- 构造器注入
package com.mtaite.study.mybatis.init;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class ConstructorBeanInit {
private final Environment environment;
@Autowired
public ConstructorBeanInit(Environment environment) {
//environment实例已初始化
this.environment = environment;
System.out.println("执行实始化-->ConstructorBeanInit"+Arrays.asList(environment.getDefaultProfiles()));
}
}
- PostConstruct(会在构造方法之后执行)
package com.mtaite.study.mybatis.init;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Arrays;
@Component
public class PostConstructBeanInit {
@Autowired
private Environment environment;
@PostConstruct
public void init() {
System.out.println("执行初始化-->PostConstructBeanInit"+Arrays.asList(this.environment.getDefaultProfiles()));
}
}
- InitializingBean(官方不推荐)
package com.mtaite.study.mybatis.init;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class InitialingzingBeanTest implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行初始化-->InitializingBean");
}
}
Bean在实例化的过程中执执行顺序为:Constructor > @PostConstruct > InitializingBean > init-method
InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet()方法。在spring初始化bean的时候,如果bean实现了InitializingBean接口,在对象的所有属性被初始化后之后才会调用afterPropertiesSet()方法。spring初始化bean肯定会在ApplicationRunner和CommandLineRunner接口调用之前。
- @Bean(initMethod)方法
尽管使用initialingBean接口可以实现初始化动作,但是Sping官方并不建议我们使用InitializingBean接口,因为它将你的代码耦合在Spring代码中,官方的建议是在bean的配置文件指定init-method方法或者在@Bean中设置init-method属性。
public class InitMethodBean {
@Autowired
private Environment environment;
public void init() {
System.out.print("执行初始化-->"+Arrays.asList(environment.getDefaultProfiles()));
}
}
@Bean(initMethod="init")
public InitMethodBean exBean() {
return new InitMethodBean();
}
Springboot初始化的顺序为总结
- 构造器方法
- @PostConstruct 注解方法
- InitializingBean的afterPropertiesSet()
- Bean定义的initMethod属性方法
- CommandLineRunner
- ApplicationRunner