✅Spring Boot 如何让你的 bean 在其他 bean 之前加载
典型回答
面对这个问题的时候,读者朋友们可能会有点懵逼,但是我们回到Bean初始化的本质上来看,Bean初始化有两个时机:
- Spring容器主动去初始化该Bean
- 其他Bean依赖该Bean,该Bean会先被初始化
从这两个出发点来思考解决问题方案的话,大概有如下几种方式:
直接依赖某Bean
如下代码所示:
@Component
public class A {
@Autowired
private B b;
}如上,在加载Bean A的时候,一定会先初始化Bean B
DependsOn
对于应用之外的二方或者三方库来说,因为我们不能修改外部库的代码,如果想要二方库的Bean在初始化之前就初始化我们内部的某个bean,就不能用第一种直接依赖的方式,可以使用@DependsOn注解来完成,如下代码所示:
@Configuration
public class BeanOrderConfiguration {
@Bean
@DependsOn("beanB")
public BeanA beanA(){
return new BeanA();
}
}当然,DependsOn注解也可以作用在@Component注解上面。
- 一方库:由你自己或你的团队开发并使用。
- 二方库:由与你有直接合作关系的合作伙伴开发,通常用于双方的合作项目中。
- 三方库:由独立于你和你公司以外的第三方开发,通常是公开可用的,广泛用于多个项目中
BeanFactoryPostProcessor
前两种方式只能对于特定的Bean生效,如果我们希望某个Bean在其他所有Bean加载之前就初始化,用前面两种方式显然是不合适的,我们这个时候,就需要从Spring容器的生命周期中去找方法。
通过上面的参考文章我们可以知道,Spring的Bean在初始化之前,会通过BeanFactoryPostProcessor#postProcessBeanFactory对工厂进行处理,我们可以依赖这个特性,在此刻提前初始化我们需要的bean
@Component
public class PrimaryBeanProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
PrimaryBean bean = beanFactory.getBean(PrimaryBean.class);
System.out.println(bean);
}
}
@Component
public class PrimaryBean {
public PrimaryBean() {
System.out.println("init primary bean");
}
@Override
public String toString() {
return "PrimaryBean{aaa}";
}
}这个时候我们通过控制台发现,PrimaryBean的初始化等级会优于其他Bean,如下所示:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.2)
2023-05-21 14:32:09.499 INFO 59380 --- [ main] cn.wxxlamp.spring.boot.Main : Starting Main using Java 1.8.0_291 on B-13CKQ05P-0131.local with PID 59380 (/Users/chenkai/code/test/target/classes started by chenkai in /Users/chenkai/code/test)
2023-05-21 14:32:09.503 INFO 59380 --- [ main] cn.wxxlamp.spring.boot.Main : No active profile set, falling back to default profiles: default
init primary bean // 希望初始化的Bean
PrimaryBean{aaa}
aware applicationContext // 系统配置Bean
initializingBean踩坑陷阱
Order只能控制同一个Bean类型中集合的顺序,不能控制不同Bean的初始化顺序,举个例子:
@Component
public class Container {
private final List<Bean> beanList;
public Container(List<Bean> beanList) {
this.beanList = beanList;
}
}
@Order(1)
@Component
class BeanA implements Bean {}
@Order(2)
@Component
class BeanB implements Bean {}这样在读取的时候,beanList中,BeanA的顺序是先于BeanB的。