Back to Javatutorial

SpringBoot自动装配(三):自动装配顺序

docs/Spring全家桶/SpringBoot源码解析/SpringBoot自动装配(三):自动装配顺序.md

1.0.019.4 KB
Original Source

springboot Զװ֮ע⣨һһУڷ @ConditionalOnBean/@ConditionalOnMissingBean עжʱٷǿҽԶװʹע⣬ @ConditionalOnBean/@ConditionalOnMissingBean ǵҪָ֮ʼ springboot Զװ˳أĽо¡

1. springboot ԶװĹ

Ҫȷǣֵ̽Զװ˳ָ class עᵽ beanFactory ˳springboot ԶװĴ¹£

  1. Զװ࣬ springboot Զװ֮Զװ һѷ
  2. ԶװDZĽҪݣ
  3. Զװ࣬ÿԶװһ²
    1. עжϵǰԶװǷװ
    2. ǰԶװװעᵽ 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 ֮ǰʼͲ쳣ˡ

ôԶװ˳ָأ

2. Զװ˳ע

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 {
    ...
}

3. Զװ

ǰᵽ@AutoConfigOrder``@AutoConfigureBefore @AutoConfigureAfter ԿԶװװ˳ôأ springboot Զװ֮Զװ һУܽ˻ȡԶװIJ 6

  1. AutoConfigurationImportSelector#getAutoConfigurationEntry(...) Զװࣻ
  2. õԶװౣ浽 autoConfigurationEntries У
  3. õ࣬Щ @EnableAutoConfiguration exclude excludeName ָģ
  4. autoConfigurationEntries תΪ LinkedHashSetΪ processedConfigurations
  5. ȥ processedConfigurations Ҫ˵ࣻ
  6. 5 õ󣬷ء

Զװڵ 6 Ӧķ AutoConfigurationImportSelector.AutoConfigurationGroup#sortAutoConfigurations£

private List<String> sortAutoConfigurations(Set<String> configurations,
        AutoConfigurationMetadata autoConfigurationMetadata) {
    // ȴ AutoConfigurationSorter 
    // Ȼ AutoConfigurationSorter.getInPriorityOrder 
    return new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata)
            .getInPriorityOrder(configurations);
}

ĴΪ

  1. AutoConfigurationSorter
  2. AutoConfigurationSorter.getInPriorityOrder

AutoConfigurationSorter Ĵ

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;
}

Ӵ ִв£

  1. classNames װ AutoConfigurationClasses
  2. ʹ @AutoConfigureOrder
  3. ʹ @AutoConfigureBefore``@AutoConfigureAfter

򹲽 3 ΣǶ orderedClassNames һǰȵǰҲ˵ûָ @AutoConfigureOrder``@AutoConfigureBefore ע⣬ͻʹ

Ǿ⼸ɡ

4. 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(...) ִ̣÷ִ£

  1. classNamesÿһ classNameIJ
  2. AutoConfigurationClass className
  3. AutoConfigurationSorter.AutoConfigurationClass#isAvailable õ available
  4. ж available required ֵһΪ tureͽӵ classes
  5. available Ϊ trueݹ鴦 className @AutoConfigureBefore @AutoConfigureAfter ָࡣ

̿ŲӣмȥҪ

  1. AutoConfigurationSorter.AutoConfigurationClass#isAvailableжϵǰ class Ƿ
  2. AutoConfigurationSorter.AutoConfigurationClass#getBeforeȡ classǰ class ҪЩ class ֮ǰ
  3. AutoConfigurationSorter.AutoConfigurationClass#getAfterȡ classǰ class ҪЩ class ֮

һһ⼸

4.1 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.AbstractProcessorAbstractProcessor 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;
    }
}

Ĵ£

  1. className תΪ classpath:xxx/xxx/Xxx.class ʽȻȥضӦԴԴڼ className Ӧ.class ļڣ׳쳣
  2. 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 ·.

4.2 AutoConfigurationSorter.AutoConfigurationClass#getBefore/getAfter

AutoConfigurationSorter.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() ̣

  1. ǰ className META-INF/spring-autoconfigure-metadata.properties ļУֱȡֵǰҲᵽspringboot ڱʱһЩעϢд뵽 META-INF/spring-autoconfigure-metadata.properties ļУ

  2. 1 ɹӵǰ class @AutoConfigureBefore ȡֵ

getAfter() getBefore() ̻һ£Ͳˡ

5. ʹ @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

6. ʹ @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 ķ̫ö£

  1. ҵǰ className ҪЩ className ֮װ䣬䱣Ϊ afterClassesҲ˵afterClasses еÿһ className Ҫڵǰ className ֮ǰװ䣻

  2. 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 עָ
  • ȡЩҪڵǰװ֮ǰװ

7. @ConditionalOnBean/@ConditionalOnMissingBean

ǰᵽ @ConditionalOnBean/@ConditionalOnMissingBean Ŀӣ˽Զװ˳󣬾ܺܺùЩˣ

  1. bean Զװࣺܿӷʽǣʹ @AutoConfigureBefore / @AutoConfigureAfter @AutoConfigureOrder ָ˳򣬱֤עе bean װ伴ɣ
  2. һͨ spring beanһԶװࣺעе bean ͨ spring beanһԶװ࣬²ôԶװĴ DeferredImportSelector ࣬Զװͨ spring bean ֮֮ עе bean Զװ࣬һͨ spring beanһҪʹã
  3. ͨ spring beanޱܿӷspring bean עᵽ beanFactory ˳򲻿ɿأʹã

8. ܽ

ܽԶװװ˳Ҫݣ

  1. ԶװAutoConfigurationImportSelector.AutoConfigurationGroup#sortAutoConfigurations
  2. ָԶװװ˳ʹ @AutoConfigureBefore / @AutoConfigureAfter @AutoConfigureOrder
  3. ʽ֣ǣ
    1. className String
    2. @AutoConfigureOrder ֵָ Integer
    3. @AutoConfigureBefore / @AutoConfigureAfter ҪעǣʽȺУĽΪ˳
  4. @ConditionalOnBean/@ConditionalOnMissingBean ָܿϣ 1. bean Զװࣺܿӷʽǣʹ @AutoConfigureBefore / @AutoConfigureAfter @AutoConfigureOrder ָ˳򣬱֤עе bean װ伴ɣ 2. һͨ spring beanһԶװࣺעе bean Ϊͨ spring bean 3. ɿأʹá

ԭӣhttps://my.oschina.net/funcy/blog/4921594 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע