|
51 | 51 | import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
52 | 52 | import org.springframework.beans.factory.support.BeanNameGenerator;
|
53 | 53 | import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
|
| 54 | +import org.springframework.context.annotation.DeferredImportSelector.Group; |
54 | 55 | import org.springframework.core.NestedIOException;
|
55 | 56 | import org.springframework.core.OrderComparator;
|
56 | 57 | import org.springframework.core.Ordered;
|
|
100 | 101 | * @author Juergen Hoeller
|
101 | 102 | * @author Phillip Webb
|
102 | 103 | * @author Sam Brannen
|
| 104 | + * @author Stephane Nicoll |
103 | 105 | * @since 3.0
|
104 | 106 | * @see ConfigurationClassBeanDefinitionReader
|
105 | 107 | */
|
@@ -543,23 +545,48 @@ private void processDeferredImportSelectors() {
|
543 | 545 | }
|
544 | 546 |
|
545 | 547 | deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
|
| 548 | + Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>(); |
| 549 | + Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>(); |
546 | 550 | for (DeferredImportSelectorHolder deferredImport : deferredImports) {
|
547 |
| - ConfigurationClass configClass = deferredImport.getConfigurationClass(); |
548 |
| - try { |
549 |
| - String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); |
550 |
| - processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); |
551 |
| - } |
552 |
| - catch (BeanDefinitionStoreException ex) { |
553 |
| - throw ex; |
554 |
| - } |
555 |
| - catch (Throwable ex) { |
556 |
| - throw new BeanDefinitionStoreException( |
557 |
| - "Failed to process import candidates for configuration class [" + |
558 |
| - configClass.getMetadata().getClassName() + "]", ex); |
559 |
| - } |
| 551 | + Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup(); |
| 552 | + DeferredImportSelectorGrouping grouping = groupings.computeIfAbsent( |
| 553 | + (group == null ? deferredImport : group), |
| 554 | + (key) -> new DeferredImportSelectorGrouping(createGroup(group))); |
| 555 | + grouping.add(deferredImport); |
| 556 | + configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), |
| 557 | + deferredImport.getConfigurationClass()); |
| 558 | + } |
| 559 | + for (DeferredImportSelectorGrouping grouping : groupings.values()) { |
| 560 | + grouping.getImports().forEach((entry) -> { |
| 561 | + ConfigurationClass configurationClass = configurationClasses.get( |
| 562 | + entry.getMetadata()); |
| 563 | + try { |
| 564 | + processImports(configurationClass, asSourceClass(configurationClass), |
| 565 | + asSourceClasses(entry.getImportClassName()), false); |
| 566 | + } |
| 567 | + catch (BeanDefinitionStoreException ex) { |
| 568 | + throw ex; |
| 569 | + } |
| 570 | + catch (Throwable ex) { |
| 571 | + throw new BeanDefinitionStoreException( |
| 572 | + "Failed to process import candidates for configuration class [" + |
| 573 | + configurationClass.getMetadata().getClassName() + "]", ex); |
| 574 | + } |
| 575 | + }); |
560 | 576 | }
|
561 | 577 | }
|
562 | 578 |
|
| 579 | + private Group createGroup(@Nullable Class<? extends Group> type) { |
| 580 | + Class<? extends Group> effectiveType = (type != null ? type |
| 581 | + : DefaultDeferredImportSelectorGroup.class); |
| 582 | + Group group = BeanUtils.instantiateClass(effectiveType); |
| 583 | + ParserStrategyUtils.invokeAwareMethods(group, |
| 584 | + ConfigurationClassParser.this.environment, |
| 585 | + ConfigurationClassParser.this.resourceLoader, |
| 586 | + ConfigurationClassParser.this.registry); |
| 587 | + return group; |
| 588 | + } |
| 589 | + |
563 | 590 | private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
|
564 | 591 | Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
|
565 | 592 |
|
@@ -677,7 +704,7 @@ SourceClass asSourceClass(@Nullable Class<?> classType) throws IOException {
|
677 | 704 | /**
|
678 | 705 | * Factory method to obtain {@link SourceClass}s from class names.
|
679 | 706 | */
|
680 |
| - private Collection<SourceClass> asSourceClasses(String[] classNames) throws IOException { |
| 707 | + private Collection<SourceClass> asSourceClasses(String... classNames) throws IOException { |
681 | 708 | List<SourceClass> annotatedClasses = new ArrayList<>(classNames.length);
|
682 | 709 | for (String className : classNames) {
|
683 | 710 | annotatedClasses.add(asSourceClass(className));
|
@@ -777,6 +804,52 @@ public DeferredImportSelector getImportSelector() {
|
777 | 804 | }
|
778 | 805 |
|
779 | 806 |
|
| 807 | + private static class DeferredImportSelectorGrouping { |
| 808 | + |
| 809 | + private final DeferredImportSelector.Group group; |
| 810 | + |
| 811 | + private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>(); |
| 812 | + |
| 813 | + DeferredImportSelectorGrouping(Group group) { |
| 814 | + this.group = group; |
| 815 | + } |
| 816 | + |
| 817 | + public void add(DeferredImportSelectorHolder deferredImport) { |
| 818 | + this.deferredImports.add(deferredImport); |
| 819 | + } |
| 820 | + |
| 821 | + /** |
| 822 | + * Return the imports defined by the group. |
| 823 | + * @return each import with its associated configuration class |
| 824 | + */ |
| 825 | + public Iterable<Group.Entry> getImports() { |
| 826 | + for (DeferredImportSelectorHolder deferredImport : this.deferredImports) { |
| 827 | + this.group.process(deferredImport.getConfigurationClass().getMetadata(), |
| 828 | + deferredImport.getImportSelector()); |
| 829 | + } |
| 830 | + return this.group.selectImports(); |
| 831 | + } |
| 832 | + } |
| 833 | + |
| 834 | + |
| 835 | + private static class DefaultDeferredImportSelectorGroup implements Group { |
| 836 | + |
| 837 | + private final List<Entry> imports = new ArrayList<>(); |
| 838 | + |
| 839 | + @Override |
| 840 | + public void process(AnnotationMetadata metadata, DeferredImportSelector selector) { |
| 841 | + for (String importClassName : selector.selectImports(metadata)) { |
| 842 | + this.imports.add(new Entry(metadata, importClassName)); |
| 843 | + } |
| 844 | + } |
| 845 | + |
| 846 | + @Override |
| 847 | + public Iterable<Entry> selectImports() { |
| 848 | + return this.imports; |
| 849 | + } |
| 850 | + } |
| 851 | + |
| 852 | + |
780 | 853 | /**
|
781 | 854 | * Simple wrapper that allows annotated source classes to be dealt with
|
782 | 855 | * in a uniform manner, regardless of how they are loaded.
|
|
0 commit comments