27
27
import java .util .HashSet ;
28
28
import java .util .Iterator ;
29
29
import java .util .LinkedHashSet ;
30
+ import java .util .LinkedList ;
30
31
import java .util .List ;
31
32
import java .util .Map ;
32
33
import java .util .Set ;
37
38
import org .springframework .beans .BeanUtils ;
38
39
import org .springframework .beans .factory .Aware ;
39
40
import org .springframework .beans .factory .BeanClassLoaderAware ;
41
+ import org .springframework .beans .factory .BeanDefinitionStoreException ;
40
42
import org .springframework .beans .factory .BeanFactory ;
41
43
import org .springframework .beans .factory .BeanFactoryAware ;
44
+ import org .springframework .beans .factory .config .BeanDefinition ;
42
45
import org .springframework .beans .factory .config .BeanDefinitionHolder ;
43
46
import org .springframework .beans .factory .config .ConfigurableBeanFactory ;
44
47
import org .springframework .beans .factory .parsing .Location ;
45
48
import org .springframework .beans .factory .parsing .Problem ;
46
49
import org .springframework .beans .factory .parsing .ProblemReporter ;
50
+ import org .springframework .beans .factory .support .AbstractBeanDefinition ;
47
51
import org .springframework .beans .factory .support .BeanDefinitionReader ;
48
52
import org .springframework .beans .factory .support .BeanDefinitionRegistry ;
49
53
import org .springframework .beans .factory .support .BeanNameGenerator ;
50
54
import org .springframework .context .ResourceLoaderAware ;
51
55
import org .springframework .core .annotation .AnnotationAttributes ;
56
+ import org .springframework .core .annotation .AnnotationAwareOrderComparator ;
52
57
import org .springframework .core .env .CompositePropertySource ;
53
58
import org .springframework .core .env .Environment ;
54
59
import org .springframework .core .env .PropertySource ;
86
91
*/
87
92
class ConfigurationClassParser {
88
93
94
+ private static final Comparator <DeferredImportSelectorHolder > DEFERRED_IMPORT_COMPARATOR =
95
+ new Comparator <ConfigurationClassParser .DeferredImportSelectorHolder >() {
96
+ public int compare (DeferredImportSelectorHolder o1 ,
97
+ DeferredImportSelectorHolder o2 ) {
98
+ return AnnotationAwareOrderComparator .INSTANCE .compare (
99
+ o1 .getImportSelector (), o2 .getImportSelector ());
100
+ }
101
+ };
102
+
89
103
protected final Log logger = LogFactory .getLog (getClass ());
90
104
91
105
private final MetadataReaderFactory metadataReaderFactory ;
@@ -112,6 +126,8 @@ class ConfigurationClassParser {
112
126
113
127
private final BeanNameGenerator beanNameGenerator ;
114
128
129
+ private final List <DeferredImportSelectorHolder > deferredImportSelectors =
130
+ new LinkedList <DeferredImportSelectorHolder >();
115
131
116
132
/**
117
133
* Create a new {@link ConfigurationClassParser} instance that will be used
@@ -131,14 +147,31 @@ public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
131
147
resourceLoader , environment , componentScanBeanNameGenerator , registry );
132
148
}
133
149
150
+ public void parse (Set <BeanDefinitionHolder > configCandidates ) {
151
+ for (BeanDefinitionHolder holder : configCandidates ) {
152
+ BeanDefinition bd = holder .getBeanDefinition ();
153
+ try {
154
+ if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition ) bd ).hasBeanClass ()) {
155
+ parse (((AbstractBeanDefinition ) bd ).getBeanClass (), holder .getBeanName ());
156
+ }
157
+ else {
158
+ parse (bd .getBeanClassName (), holder .getBeanName ());
159
+ }
160
+ }
161
+ catch (IOException ex ) {
162
+ throw new BeanDefinitionStoreException ("Failed to load bean class: " + bd .getBeanClassName (), ex );
163
+ }
164
+ }
165
+ processDeferredImportSelectors ();
166
+ }
134
167
135
168
/**
136
169
* Parse the specified {@link Configuration @Configuration} class.
137
170
* @param className the name of the class to parse
138
171
* @param beanName may be null, but if populated represents the bean id
139
172
* (assumes that this configuration class was configured via XML)
140
173
*/
141
- public void parse (String className , String beanName ) throws IOException {
174
+ protected void parse (String className , String beanName ) throws IOException {
142
175
ConfigurationMetadataReader reader = new ConfigurationMetadataReader (className );
143
176
processConfigurationClass (reader .getConfigurationClass (beanName ));
144
177
}
@@ -148,7 +181,7 @@ public void parse(String className, String beanName) throws IOException {
148
181
* @param clazz the Class to parse
149
182
* @param beanName must not be null (as of Spring 3.1.1)
150
183
*/
151
- public void parse (Class <?> clazz , String beanName ) throws IOException {
184
+ protected void parse (Class <?> clazz , String beanName ) throws IOException {
152
185
processConfigurationClass (new ConfigurationClass (clazz , beanName ));
153
186
}
154
187
@@ -323,6 +356,21 @@ private Set<String> getImports(String className, Set<String> imports, Set<String
323
356
return imports ;
324
357
}
325
358
359
+ private void processDeferredImportSelectors () {
360
+ Collections .sort (this .deferredImportSelectors , DEFERRED_IMPORT_COMPARATOR );
361
+ for (DeferredImportSelectorHolder deferredImport : this .deferredImportSelectors ) {
362
+ try {
363
+ ConfigurationClass configClass = deferredImport .getConfigurationClass ();
364
+ String [] imports = deferredImport .getImportSelector ().selectImports (configClass .getMetadata ());
365
+ processImport (configClass , imports , false );
366
+ }
367
+ catch (IOException ex ) {
368
+ throw new BeanDefinitionStoreException ("Failed to load bean class: " , ex );
369
+ }
370
+ }
371
+ deferredImportSelectors .clear ();
372
+ }
373
+
326
374
private void processImport (ConfigurationClass configClass , String [] classesToImport , boolean checkForCircularImports ) throws IOException {
327
375
if (checkForCircularImports && this .importStack .contains (configClass )) {
328
376
this .problemReporter .error (new CircularImportProblem (configClass , this .importStack , configClass .getMetadata ()));
@@ -339,7 +387,12 @@ private void processImport(ConfigurationClass configClass, String[] classesToImp
339
387
ImportSelector selector = BeanUtils .instantiateClass (
340
388
this .resourceLoader .getClassLoader ().loadClass (candidate ), ImportSelector .class );
341
389
invokeAwareMethods (selector );
342
- processImport (configClass , selector .selectImports (importingClassMetadata ), false );
390
+ if (selector instanceof DeferredImportSelector ) {
391
+ this .deferredImportSelectors .add (new DeferredImportSelectorHolder (
392
+ configClass , (DeferredImportSelector ) selector ));
393
+ } else {
394
+ processImport (configClass , selector .selectImports (importingClassMetadata ), false );
395
+ }
343
396
}
344
397
catch (ClassNotFoundException ex ) {
345
398
throw new IllegalStateException (ex );
@@ -572,4 +625,25 @@ public void log() {
572
625
logger .debug (message , t );
573
626
}
574
627
}
628
+
629
+
630
+ private static class DeferredImportSelectorHolder {
631
+
632
+ private ConfigurationClass configurationClass ;
633
+
634
+ private DeferredImportSelector importSelector ;
635
+
636
+ public DeferredImportSelectorHolder (ConfigurationClass configurationClass , DeferredImportSelector importSelector ) {
637
+ this .configurationClass = configurationClass ;
638
+ this .importSelector = importSelector ;
639
+ }
640
+
641
+ public ConfigurationClass getConfigurationClass () {
642
+ return configurationClass ;
643
+ }
644
+
645
+ public DeferredImportSelector getImportSelector () {
646
+ return importSelector ;
647
+ }
648
+ }
575
649
}
0 commit comments