前言
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");}
}