前言
SpringBoot通过@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter注解,控制自动配置类的实例化顺序。
Spring中控制Bean的实例化顺序
Spring中默认实例化顺序
创建实体类A、B、C
@Component
public class A {
public A() {
System.out.println("A construct");
}
}
@Component
public class B {
public B() {
System.out.println("B construct");
}
}
@Component
public class C {
public C() {
System.out.println("C construct");
}
}
启动SpringBoot
实例化顺序: A > B > C
Spring中指定实例化顺序(C > B > A)
修改实体类A、B、C
@Component
@DependsOn("b")
public class A {
public A() {
System.out.println("A construct");
}
}
@Component
@DependsOn("c")
public class B {
public B() {
System.out.println("B construct");
}
}
@Component
public class C {
public C() {
System.out.println("C construct");
}
}
启动SpringBoot
实例化顺序: C > B > A
SpringBoot中控制自动配置类的实例化顺序
SpringBoot中默认实例化顺序
在 resources 文件夹下创建 META-INF 文件夹,在 META-INF 文件夹下创建 spring.factories 文件,整体结构如下:
spring.factories 明细如下:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.ys.boot.auto.D,\
com.ys.boot.auto.E,\
com.ys.boot.auto.F
创建实体类D、E、F
public class D {
public D() {
System.out.println("D construct");
}
}
public class E {
public E() {
System.out.println("E construct");
}
}
public class F {
public F() {
System.out.println("F construct");
}
}
启动SpringBoot
实例化顺序: D > E > F
使用@DependsOn解决实例化顺序?
修改实体类D、E、F
@DependsOn("e")
public class D {
public D() {
System.out.println("D construct");
}
}
@DependsOn("f")
public class E {
public E() {
System.out.println("E construct");
}
}
public class F {
public F() {
System.out.println("F construct");
}
}
启动SpringBoot
抛出 org.springframework.beans.factory.NoSuchBeanDefinitionException
异常原因 : 一般情况下,自动配置的类都不是当前项目的文件,即Spring不会将相关文件扫描成BeanDefinition对象。当我们使用@DependsOn注解的时候,Spring就尝从当前环境中查找或实例化指定名称的Bean,因为找不到相关BeanDefinition对象,所以抛出异常。
SpringBoot中指定实例化顺序(方式一)
修改实体类D、E、F
@AutoConfigureOrder(3)
public class D {
public D() {
System.out.println("D construct");
}
}
@AutoConfigureOrder(2)
public class E {
public E() {
System.out.println("E construct");
}
}
@AutoConfigureOrder(1)
public class F {
public F() {
System.out.println("F construct");
}
}
启动SpringBoot
实例化顺序: F > E > D
SpringBoot中指定实例化顺序(方式二)
修改实体类D、E、F
@AutoConfigureAfter(E.class)
public class D {
public D() {
System.out.println("D construct");
}
}
@AutoConfigureAfter(F.class)
public class E {
public E() {
System.out.println("E construct");
}
}
public class F {
public F() {
System.out.println("F construct");
}
}
启动SpringBoot
实例化顺序: F > E > D
源码简析
AutoConfigurationSorter#getInPriorityOrder
List<String> getInPriorityOrder(Collection<String> classNames) {
AutoConfigurationSorter.AutoConfigurationClasses classes = new AutoConfigurationSorter.AutoConfigurationClasses(this.metadataReaderFactory,
this.autoConfigurationMetadata, classNames);
List<String> orderedClassNames = new ArrayList<>(classNames);
// 最初按字母顺序排序
Collections.sort(orderedClassNames);
// 根据@AutoConfigureOrder的order值排序,值越小,优先级越高
orderedClassNames.sort((o1, o2) -> {
int i1 = classes.get(o1).getOrder();
int i2 = classes.get(o2).getOrder();
return Integer.compare(i1, i2);
});
// 根据@AutoConfigureBefore、@AutoConfigureAfter注解指定的顺序排序
orderedClassNames = sortByAnnotation(classes, orderedClassNames);
return orderedClassNames;
}
排序优先级 :
- 根据@AutoConfigureBefore、@AutoConfigureAfter注解指定的顺序排序
- 根据@AutoConfigureOrder的order值排序
- 按字母顺序排序
@AutoConfigureBefore、@AutoConfigureAfter配置不当可能会抛出异常,案例演示如下:
@AutoConfigureAfter(E.class)
public class D {
public D() {
System.out.println("D construct");
}
}
@AutoConfigureAfter(F.class)
public class E {
public E() {
System.out.println("E construct");
}
}
@AutoConfigureAfter(D.class)
public class F {
public F() {
System.out.println("F construct");
}
}