docs/Spring全家桶/SpringBoot源码解析/SpringBoot自动装配(三):自动装配顺序.md
springboot Զװ֮ע⣨һһУڷ @ConditionalOnBean/@ConditionalOnMissingBean עжʱٷǿҽԶװʹע⣬ @ConditionalOnBean/@ConditionalOnMissingBean ǵҪָ֮ʼ springboot Զװ˳أĽо¡
Ҫȷǣֵ̽Զװ˳ָ class עᵽ beanFactory ˳springboot ԶװĴ¹£
beanFactory Сٻص @ConditionalOnBean/@ConditionalOnMissingBeanԶװࣺ
// AԶװ
@Configuration
public class A {
@Bean
@ConditionalOnMissingBean("b1")
public A1 a1() {
return new A1();
}
}
// BԶװ
@Configuration
public class B {
@Bean
public B1 b1() {
return new b1();
}
}
a1 b1 ͬԶװгʼ a1 ֻ b1 ʱŻʼܽ springboot ԶװIJ裬ֻҪָ b1 a1 ֮ǰʼͲ쳣ˡ
ôԶװ˳ָأ
springboot ΪṩԶװֶΣ
@AutoConfigOrder@AutoConfigureBefore @AutoConfigureAfterעԶװˣ@AutoConfigOrder ָװ˳ͬ spring ṩ @Order ƣ@AutoConfigureBefore @AutoConfigureAfter ָ classʾĸ class ֮ǰ֮װ䡣
صʾǿָװ˳
// AԶװ
@Configuration
// B.class֮Զװ
@AutoConfigureAfter(B.class)
public class A {
@Bean
@ConditionalOnMissingBean("b1")
public A1 a1() {
...
}
}
// BԶװ
@Configuration
public class B {
...
}
ǰᵽ@AutoConfigOrder``@AutoConfigureBefore @AutoConfigureAfter ԿԶװװ˳ôأ springboot Զװ֮Զװ һУܽ˻ȡԶװIJ 6
AutoConfigurationImportSelector#getAutoConfigurationEntry(...) ԶװࣻautoConfigurationEntries У@EnableAutoConfiguration exclude excludeName ָģautoConfigurationEntries תΪ LinkedHashSetΪ processedConfigurationsprocessedConfigurations Ҫ˵ࣻԶװڵ 6 Ӧķ AutoConfigurationImportSelector.AutoConfigurationGroup#sortAutoConfigurations£
private List<String> sortAutoConfigurations(Set<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
// ȴ AutoConfigurationSorter
// Ȼ AutoConfigurationSorter.getInPriorityOrder
return new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata)
.getInPriorityOrder(configurations);
}
ĴΪ
AutoConfigurationSorterAutoConfigurationSorter.getInPriorityOrderAutoConfigurationSorter Ĵ
class AutoConfigurationSorter {
private final MetadataReaderFactory metadataReaderFactory;
private final AutoConfigurationMetadata autoConfigurationMetadata;
/**
* 췽
* ֻǶԴIJиֵǸֵΪԱ
*/
AutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory,
AutoConfigurationMetadata autoConfigurationMetadata) {
Assert.notNull(metadataReaderFactory, "MetadataReaderFactory must not be null");
this.metadataReaderFactory = metadataReaderFactory;
this.autoConfigurationMetadata = autoConfigurationMetadata;
}
...
}
ԿAutoConfigurationSorter Ĺ췽ûʲôʵԵIJĹؼÿ AutoConfigurationSorter.getInPriorityOrder ÷Ĵ£
List<String> getInPriorityOrder(Collection<String> classNames) {
// 1\. classNames װ AutoConfigurationClasses
AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory,
this.autoConfigurationMetadata, classNames);
List<String> orderedClassNames = new ArrayList<>(classNames);
// 2\.
Collections.sort(orderedClassNames);
// 3\. ʹ @AutoConfigureOrder
orderedClassNames.sort((o1, o2) -> {
int i1 = classes.get(o1).getOrder();
int i2 = classes.get(o2).getOrder();
return Integer.compare(i1, i2);
});
// 4\. ʹ @AutoConfigureBefore@AutoConfigureAfter
orderedClassNames = sortByAnnotation(classes, orderedClassNames);
return orderedClassNames;
}
Ӵ ִв£
classNames װ AutoConfigurationClasses@AutoConfigureOrder@AutoConfigureBefore``@AutoConfigureAfter 3 ΣǶ orderedClassNames һǰȵǰҲ˵ûָ @AutoConfigureOrder``@AutoConfigureBefore ע⣬ͻʹ
Ǿ⼸ɡ
classNames װ AutoConfigurationClassesòλ AutoConfigurationSorter.AutoConfigurationClasses#AutoConfigurationClasses £
private static class AutoConfigurationClasses {
//
private final Map<String, AutoConfigurationClass> classes = new HashMap<>();
/**
* 췽
*/
AutoConfigurationClasses(MetadataReaderFactory metadataReaderFactory,
AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames) {
// з
addToClasses(metadataReaderFactory, autoConfigurationMetadata, classNames, true);
}
/**
* ࣬ǽװ AutoConfigurationClassӵΪ classes Map
* classNames ȥųԶװ
*/
private void addToClasses(MetadataReaderFactory metadataReaderFactory,
AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames,
boolean required) {
for (String className : classNames) {
if (!this.classes.containsKey(className)) {
// className װ AutoConfigurationClass
AutoConfigurationClass autoConfigurationClass = new AutoConfigurationClass(
className, metadataReaderFactory, autoConfigurationMetadata);
boolean available = autoConfigurationClass.isAvailable();
// @AutoConfigureBefore @AutoConfigureAfter ǵ required Ϊ false
if (required || available) {
this.classes.put(className, autoConfigurationClass);
}
if (available) {
// ݹ
addToClasses(metadataReaderFactory, autoConfigurationMetadata,
autoConfigurationClass.getBefore(), false);
addToClasses(metadataReaderFactory, autoConfigurationMetadata,
autoConfigurationClass.getAfter(), false);
}
}
}
}
...
}
ϴ
AutoConfigurationClasses һԱclasses Map``key StringҲ className``value AutoConfigurationClassҲ className İࣩ;AutoConfigurationClasses Ĺ췽 addToClasses(...) ÷ classNamesװ AutoConfigurationClass ٱ浽 classes Сڷ addToClasses(...) ľǰ AutoConfigurationClass Ǹɶ
Կ AutoConfigurationClass İװһ @AutoConfigureBefore @AutoConfigureAfter ָ࣬Լṩ˸ @AutoConfigureOrder @AutoConfigureBefore``@AutoConfigureAfter صһЩ
ٻعͷ addToClasses(...) ִ̣÷ִ£
classNamesÿһ classNameIJAutoConfigurationClass classNameAutoConfigurationSorter.AutoConfigurationClass#isAvailable õ availableavailable required ֵһΪ tureͽӵ classesavailable Ϊ trueݹ鴦 className @AutoConfigureBefore @AutoConfigureAfter ָࡣ̿ŲӣмȥҪ
AutoConfigurationSorter.AutoConfigurationClass#isAvailableжϵǰ class ǷAutoConfigurationSorter.AutoConfigurationClass#getBeforeȡ classǰ class ҪЩ class ֮ǰAutoConfigurationSorter.AutoConfigurationClass#getAfterȡ classǰ class ҪЩ class ֮һһ⼸
AutoConfigurationSorter.AutoConfigurationClass#isAvailableжϵǰ class ǷڵǰĿ classpath У룺
boolean isAvailable() {
try {
if (!wasProcessed()) {
getAnnotationMetadata();
}
return true;
}
catch (Exception ex) {
return false;
}
}
벻࣬ǵ wasProcessed() ٵ getAnnotationMetadata()ҪעǣgetAnnotationMetadata() ܻ׳쳣Ƹ쳣Ҳ᷵ false.
Ǽ AutoConfigurationSorter.AutoConfigurationClass#wasProcessed
private boolean wasProcessed() {
return (this.autoConfigurationMetadata != null
// ж META-INF/spring-autoconfigure-metadata.properties ļǷڸ
&& this.autoConfigurationMetadata.wasProcessed(this.className));
}
Ҫ AutoConfigurationMetadataLoader.PropertiesAutoConfigurationMetadata#wasProcessed жϣ
@Override
public boolean wasProcessed(String className) {
// ж properties ǷڶӦ className
return this.properties.containsKey(className);
}
Կж properties Ƿ className``properties META-INF/spring-autoconfigure-metadata.propertiesʾ£
ҪעǣļԴDzڵģڱʱдģڸļд롢ص properties ̣ľͲչˣṩ˼·
ļд룺ڴʱspringboot ὫԶװһЩϢ (磬@ConditionalOnClass ָ class``@ConditionalOnBean ָ bean``@AutoConfigureBefore @AutoConfigureAfter ָ class ) д뵽 META-INF/spring-autoconfigure-metadata.properties ļУΪ AutoConfigureAnnotationProcessor javax.annotation.processing.AbstractProcessor ࣬ AbstractProcessor jdk ṩڱڶעд
ļļأ AutoConfigurationImportSelector.AutoConfigurationGroup#process е AutoConfigurationImportSelector#getAutoConfigurationEntry ʱᴫ AutoConfigurationMetadataļ META-INF/spring-autoconfigure-metadata.properties еݾǴص AutoConfigurationMetadataLoader.PropertiesAutoConfigurationMetadata#properties еģ
ЩɼAutoConfigurationMetadataLoader.PropertiesAutoConfigurationMetadata#wasProcessed ʵϾж META-INF/spring-autoconfigure-metadata.properties ļǷ className á
ǻص AutoConfigurationSorter.AutoConfigurationClass#isAvailableһgetAnnotationMetadata()÷λ AutoConfigurationSorter.AutoConfigurationClass У£
private AnnotationMetadata getAnnotationMetadata() {
if (this.annotationMetadata == null) {
try {
// `className`ӦԴ className ӦԴʱ׳쳣
MetadataReader metadataReader = this.metadataReaderFactory
.getMetadataReader(this.className);
this.annotationMetadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
throw new IllegalStateException(...);
}
}
return this.annotationMetadata;
}
SimpleMetadataReaderFactory#getMetadataReader(String)
@Override
/**
* ȡ className Ӧ .class ļ
* .class ļڣͱ쳣ˣIOException
*/
public MetadataReader getMetadataReader(String className) throws IOException {
try {
// תƣ"classpath:xxx/xxx/Xxx.class"
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX
+ lassUtils.convertClassNameToResourcePath(className)
+ ClassUtils.CLASS_FILE_SUFFIX;
// ȡԴĬϵ resourceLoader Ϊ classLoader
Resource resource = this.resourceLoader.getResource(resourcePath);
// resource ת MetadataReader ھͻ׳쳣IOException
return getMetadataReader(resource);
}
catch (FileNotFoundException ex) {
// пڲٰ࣬ڲʽһ
int lastDotIndex = className.lastIndexOf('.');
if (lastDotIndex != -1) {
String innerClassName = className.substring(0, lastDotIndex) + '$'
+ className.substring(lastDotIndex + 1);
// תƣ"classpath:xxx/Xxx$Xxx.class"
String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(innerClassName)
+ ClassUtils.CLASS_FILE_SUFFIX;
Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath);
// жǷڣڻǻᱨ쳣ģIOException
if (innerClassResource.exists()) {
return getMetadataReader(innerClassResource);
}
}
throw ex;
}
}
Ĵ£
className תΪ classpath:xxx/xxx/Xxx.class ʽȻȥضӦԴԴڼ className Ӧ.class ļڣ׳쳣catch УΪ˷ֹ className ڲ࣬Ὣ className תΪ classpath:xxx/Xxx$Xxx.class ʽȻټһԴԴڣֱӷأ쳣ףǾˣgetAnnotationMetadata() жϵǰ className Ӧ.class Ŀ classpath ·Ƿڡ
ܽ£
AutoConfigurationSorter.AutoConfigurationClass#wasProcessedǰ className Ƿ META-INF/spring-autoconfigure-metadata.properties ļAutoConfigurationSorter.AutoConfigurationClass#isAvailableǰ className Ӧ.class ļǷյĽۣAutoConfigurationSorter.AutoConfigurationClass#isAvailable жϵǰ className Ӧ.class ļĿ classpath ·.
AutoConfigurationSorter.AutoConfigurationClass#getBefore/getAfterAutoConfigurationSorter.AutoConfigurationClass getAfter() getBefore()
Set<String> getBefore() {
if (this.before == null) {
this.before = (wasProcessed()
// `META-INF/spring-autoconfigure-metadata.properties` ļУֱӻȡֵ
? this.autoConfigurationMetadata.getSet(this.className, "AutoConfigureBefore",
Collections.emptySet())
// @AutoConfigureBefore עϻȡ
: getAnnotationValue(AutoConfigureBefore.class));
}
return this.before;
}
Set<String> getAfter() {
if (this.after == null) {
this.after = (wasProcessed()
// `META-INF/spring-autoconfigure-metadata.properties` ļУֱӻȡֵ
? this.autoConfigurationMetadata.getSet(this.className, "AutoConfigureAfter",
Collections.emptySet())
// @AutoConfigureAfter עϻȡ
: getAnnotationValue(AutoConfigureAfter.class));
}
return this.after;
}
/**
* @AutoConfigureBefore/@AutoConfigureAfter עлȡֵvalue name ֵָ
*/
private Set<String> getAnnotationValue(Class<?> annotation) {
Map<String, Object> attributes = getAnnotationMetadata()
.getAnnotationAttributes(annotation.getName(), true);
if (attributes == null) {
return Collections.emptySet();
}
Set<String> value = new LinkedHashSet<>();
Collections.addAll(value, (String[]) attributes.get("value"));
Collections.addAll(value, (String[]) attributes.get("name"));
return value;
}
ڴʽһ£ȿ getBefore() ̣
ǰ className META-INF/spring-autoconfigure-metadata.properties ļУֱȡֵǰҲᵽspringboot ڱʱһЩעϢд뵽 META-INF/spring-autoconfigure-metadata.properties ļУ
1 ɹӵǰ class @AutoConfigureBefore ȡֵ
getAfter() getBefore() ̻һ£Ͳˡ
@AutoConfigureOrderǻص AutoConfigurationSorter#getInPriorityOrder @AutoConfigureOrder ̣
List<String> getInPriorityOrder(Collection<String> classNames) {
...
orderedClassNames.sort((o1, o2) -> {
int i1 = classes.get(o1).getOrder();
int i2 = classes.get(o2).getOrder();
return Integer.compare(i1, i2);
});
...
}
ʹõ List#sort``sort(...) IJΪ ComparatorָӴͨ getOrder() ȡǰ˳ʹõ Integer ıȽϹ getOrder() ĹؼԾ͵ķ AutoConfigurationSorter.AutoConfigurationClass#getOrder£
private int getOrder() {
// ж META-INF/spring-autoconfigure-metadata.properties ļǷڵǰ className
if (wasProcessed()) {
// ڣʹļָ˳ʹĬ˳
return this.autoConfigurationMetadata.getInteger(this.className,
"AutoConfigureOrder", AutoConfigureOrder.DEFAULT_ORDER);
}
// ڵȡ @AutoConfigureOrder עָ˳
Map<String, Object> attributes = getAnnotationMetadata()
.getAnnotationAttributes(AutoConfigureOrder.class.getName());
// @AutoConfigureOrder δãʹĬ˳
return (attributes != null) ? (Integer) attributes.get("value")
: AutoConfigureOrder.DEFAULT_ORDER;
}
DZȽϼģǻȡ @AutoConfigureOrder עָ˳û @AutoConfigureOrder ע⣬ʹĬ˳Ĭ˳ AutoConfigureOrder.DEFAULT_ORDER ֵΪ 0
@AutoConfigureBefore``@AutoConfigureAfterĵ @AutoConfigureBefore @AutoConfigureAfter עˣӦķΪ AutoConfigurationSorter#sortByAnnotation£
/**
*
* ʵֻһЩݣɻ doSortByAfterAnnotation(...)
*/
private List<String> sortByAnnotation(AutoConfigurationClasses classes, List<String> classNames) {
// Ҫ className
List<String> toSort = new ArrayList<>(classNames);
toSort.addAll(classes.getAllNames());
// õ className
Set<String> sorted = new LinkedHashSet<>();
// е className
Set<String> processing = new LinkedHashSet<>();
while (!toSort.isEmpty()) {
// ķ
doSortByAfterAnnotation(classes, toSort, sorted, processing, null);
}
// ڼ sorted У classNames еԪؽᱻƳ
sorted.retainAll(classNames);
return new ArrayList<>(sorted);
}
/**
* ķ
*/
private void doSortByAfterAnnotation(AutoConfigurationClasses classes, List<String> toSort,
Set<String> sorted, Set<String> processing, String current) {
if (current == null) {
current = toSort.remove(0);
}
// ʹ processing жǷѭȽϣ磬A after B B after A
processing.add(current);
// classes.getClassesRequestedAfterǰ className ҪЩ className ִ֮
for (String after : classes.getClassesRequestedAfter(current)) {
Assert.state(!processing.contains(after),
"AutoConfigure cycle detected between " + current + " and " + after);
if (!sorted.contains(after) && toSort.contains(after)) {
// ݹ
doSortByAfterAnnotation(classes, toSort, sorted, processing, after);
}
}
processing.remove(current);
// ӵ
sorted.add(current);
}
AutoConfigurationSorter#sortByAnnotation ṩ˱ݵĽṹ AutoConfigurationSorter#doSortByAfterAnnotation ķ̫ö£
ҵǰ className ҪЩ className ֮װ䣬䱣Ϊ afterClassesҲ˵afterClasses еÿһ className Ҫڵǰ className ֮ǰװ䣻
afterClassesÿһ className afterClassesݹȥѭȽϵ£ձȻһ className afterClasses ΪգͰ className 뵽ĽṹС
ȡ afterClasses IJΪ AutoConfigurationSorter.AutoConfigurationClasses#getClassesRequestedAfter£
Set<String> getClassesRequestedAfter(String className) {
// ǰࣺȡЩִ֮Уǻȡ @AutoConfigureAfter עָ
Set<String> classesRequestedAfter = new LinkedHashSet<>(get(className).getAfter());
// ࣺҪǰִе
this.classes.forEach((name, autoConfigurationClass) -> {
if (autoConfigurationClass.getBefore().contains(className)) {
classesRequestedAfter.add(name);
}
});
return classesRequestedAfter;
}
Ӵ afterClasses ݣ
@AutoConfigureAfter עָ@ConditionalOnBean/@ConditionalOnMissingBeanǰᵽ @ConditionalOnBean/@ConditionalOnMissingBean Ŀӣ˽Զװ˳ܺܺùЩˣ
bean Զװࣺܿӷʽǣʹ @AutoConfigureBefore / @AutoConfigureAfter @AutoConfigureOrder ָ˳֤עе bean װ伴ɣspring beanһԶװࣺעе bean ͨ spring beanһԶװ࣬²ôԶװĴ DeferredImportSelector ࣬Զװͨ spring bean ֮֮ עе bean Զװ࣬һͨ spring beanһҪʹãspring beanޱܿӷspring bean עᵽ beanFactory ˳ɿأʹãܽԶװװ˳Ҫݣ
AutoConfigurationImportSelector.AutoConfigurationGroup#sortAutoConfigurations@AutoConfigureBefore / @AutoConfigureAfter @AutoConfigureOrderString ṩ@AutoConfigureOrder ֵָ Integer ṩ@AutoConfigureBefore / @AutoConfigureAfter ҪעǣʽȺУĽΪ˳@ConditionalOnBean/@ConditionalOnMissingBean ָܿϣ
1. bean Զװࣺܿӷʽǣʹ @AutoConfigureBefore / @AutoConfigureAfter @AutoConfigureOrder ָ˳֤עе bean װ伴ɣ
2. һͨ spring beanһԶװࣺעе bean Ϊͨ spring bean
3. ɿأʹáԭӣhttps://my.oschina.net/funcy/blog/4921594 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע