1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.context.annotation;
18
19 import java.beans.PropertyDescriptor;
20 import java.util.Arrays;
21 import java.util.HashSet;
22 import java.util.LinkedHashMap;
23 import java.util.LinkedHashSet;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
31 import org.springframework.beans.PropertyValues;
32 import org.springframework.beans.factory.BeanClassLoaderAware;
33 import org.springframework.beans.factory.BeanDefinitionStoreException;
34 import org.springframework.beans.factory.BeanFactory;
35 import org.springframework.beans.factory.BeanFactoryAware;
36 import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
37 import org.springframework.beans.factory.config.BeanDefinition;
38 import org.springframework.beans.factory.config.BeanDefinitionHolder;
39 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
40 import org.springframework.beans.factory.config.BeanPostProcessor;
41 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
42 import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
43 import org.springframework.beans.factory.config.SingletonBeanRegistry;
44 import org.springframework.beans.factory.parsing.FailFastProblemReporter;
45 import org.springframework.beans.factory.parsing.PassThroughSourceExtractor;
46 import org.springframework.beans.factory.parsing.ProblemReporter;
47 import org.springframework.beans.factory.parsing.SourceExtractor;
48 import org.springframework.beans.factory.support.AbstractBeanDefinition;
49 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
50 import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
51 import org.springframework.beans.factory.support.BeanNameGenerator;
52 import org.springframework.beans.factory.support.RootBeanDefinition;
53 import org.springframework.context.EnvironmentAware;
54 import org.springframework.context.ResourceLoaderAware;
55 import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
56 import org.springframework.core.Ordered;
57 import org.springframework.core.PriorityOrdered;
58 import org.springframework.core.env.Environment;
59 import org.springframework.core.io.DefaultResourceLoader;
60 import org.springframework.core.io.ResourceLoader;
61 import org.springframework.core.type.AnnotationMetadata;
62 import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
63 import org.springframework.core.type.classreading.MetadataReaderFactory;
64 import org.springframework.util.Assert;
65 import org.springframework.util.ClassUtils;
66
67 import static org.springframework.context.annotation.AnnotationConfigUtils.*;
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
88 PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
89
90 private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
91 ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
92
93 private static final String IMPORT_REGISTRY_BEAN_NAME =
94 ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
95
96 private static final String ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME =
97 ConfigurationClassPostProcessor.class.getName() + ".enhancedConfigurationProcessor";
98
99
100 private final Log logger = LogFactory.getLog(getClass());
101
102 private SourceExtractor sourceExtractor = new PassThroughSourceExtractor();
103
104 private ProblemReporter problemReporter = new FailFastProblemReporter();
105
106 private Environment environment;
107
108 private ResourceLoader resourceLoader = new DefaultResourceLoader();
109
110 private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
111
112 private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
113
114 private boolean setMetadataReaderFactoryCalled = false;
115
116 private final Set<Integer> registriesPostProcessed = new HashSet<Integer>();
117
118 private final Set<Integer> factoriesPostProcessed = new HashSet<Integer>();
119
120 private ConfigurationClassBeanDefinitionReader reader;
121
122 private boolean localBeanNameGeneratorSet = false;
123
124
125 private BeanNameGenerator componentScanBeanNameGenerator = new AnnotationBeanNameGenerator();
126
127
128 private BeanNameGenerator importBeanNameGenerator = new AnnotationBeanNameGenerator() {
129 @Override
130 protected String buildDefaultBeanName(BeanDefinition definition) {
131 return definition.getBeanClassName();
132 }
133 };
134
135
136 @Override
137 public int getOrder() {
138 return Ordered.LOWEST_PRECEDENCE;
139 }
140
141
142
143
144
145 public void setSourceExtractor(SourceExtractor sourceExtractor) {
146 this.sourceExtractor = (sourceExtractor != null ? sourceExtractor : new PassThroughSourceExtractor());
147 }
148
149
150
151
152
153
154
155 public void setProblemReporter(ProblemReporter problemReporter) {
156 this.problemReporter = (problemReporter != null ? problemReporter : new FailFastProblemReporter());
157 }
158
159
160
161
162
163
164 public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
165 Assert.notNull(metadataReaderFactory, "MetadataReaderFactory must not be null");
166 this.metadataReaderFactory = metadataReaderFactory;
167 this.setMetadataReaderFactoryCalled = true;
168 }
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
188 Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
189 this.localBeanNameGeneratorSet = true;
190 this.componentScanBeanNameGenerator = beanNameGenerator;
191 this.importBeanNameGenerator = beanNameGenerator;
192 }
193
194 @Override
195 public void setEnvironment(Environment environment) {
196 Assert.notNull(environment, "Environment must not be null");
197 this.environment = environment;
198 }
199
200 @Override
201 public void setResourceLoader(ResourceLoader resourceLoader) {
202 Assert.notNull(resourceLoader, "ResourceLoader must not be null");
203 this.resourceLoader = resourceLoader;
204 }
205
206 @Override
207 public void setBeanClassLoader(ClassLoader beanClassLoader) {
208 this.beanClassLoader = beanClassLoader;
209 if (!this.setMetadataReaderFactoryCalled) {
210 this.metadataReaderFactory = new CachingMetadataReaderFactory(beanClassLoader);
211 }
212 }
213
214
215
216
217
218 @Override
219 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
220 RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
221 iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
222 registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);
223
224 RootBeanDefinition ecbpp = new RootBeanDefinition(EnhancedConfigurationBeanPostProcessor.class);
225 ecbpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
226 registry.registerBeanDefinition(ENHANCED_CONFIGURATION_PROCESSOR_BEAN_NAME, ecbpp);
227
228 int registryId = System.identityHashCode(registry);
229 if (this.registriesPostProcessed.contains(registryId)) {
230 throw new IllegalStateException(
231 "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
232 }
233 if (this.factoriesPostProcessed.contains(registryId)) {
234 throw new IllegalStateException(
235 "postProcessBeanFactory already called on this post-processor against " + registry);
236 }
237 this.registriesPostProcessed.add(registryId);
238
239 processConfigBeanDefinitions(registry);
240 }
241
242
243
244
245
246 @Override
247 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
248 int factoryId = System.identityHashCode(beanFactory);
249 if (this.factoriesPostProcessed.contains(factoryId)) {
250 throw new IllegalStateException(
251 "postProcessBeanFactory already called on this post-processor against " + beanFactory);
252 }
253 this.factoriesPostProcessed.add(factoryId);
254 if (!this.registriesPostProcessed.contains(factoryId)) {
255
256
257 processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
258 }
259 enhanceConfigurationClasses(beanFactory);
260 }
261
262
263
264
265
266 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
267 Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<BeanDefinitionHolder>();
268 String[] candidateNames = registry.getBeanDefinitionNames();
269
270 for (String beanName : candidateNames) {
271 BeanDefinition beanDef = registry.getBeanDefinition(beanName);
272 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
273 ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
274 if (logger.isDebugEnabled()) {
275 logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
276 }
277 }
278 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
279 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
280 }
281 }
282
283
284 if (configCandidates.isEmpty()) {
285 return;
286 }
287
288
289 SingletonBeanRegistry singletonRegistry = null;
290 if (registry instanceof SingletonBeanRegistry) {
291 singletonRegistry = (SingletonBeanRegistry) registry;
292 if (!this.localBeanNameGeneratorSet && singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
293 BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
294 this.componentScanBeanNameGenerator = generator;
295 this.importBeanNameGenerator = generator;
296 }
297 }
298
299
300 ConfigurationClassParser parser = new ConfigurationClassParser(
301 this.metadataReaderFactory, this.problemReporter, this.environment,
302 this.resourceLoader, this.componentScanBeanNameGenerator, registry);
303
304 Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
305 do {
306 parser.parse(configCandidates);
307 parser.validate();
308
309 Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
310 configClasses.removeAll(alreadyParsed);
311
312
313 if (this.reader == null) {
314 this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor,
315 this.problemReporter, this.metadataReaderFactory, this.resourceLoader, this.environment,
316 this.importBeanNameGenerator, parser.getImportRegistry());
317 }
318 this.reader.loadBeanDefinitions(configClasses);
319 alreadyParsed.addAll(configClasses);
320
321 configCandidates.clear();
322 if (registry.getBeanDefinitionCount() > candidateNames.length) {
323 String[] newCandidateNames = registry.getBeanDefinitionNames();
324 Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));
325 Set<String> alreadyParsedClasses = new HashSet<String>();
326 for (ConfigurationClass configurationClass : alreadyParsed) {
327 alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
328 }
329 for (String candidateName : newCandidateNames) {
330 if (!oldCandidateNames.contains(candidateName)) {
331 BeanDefinition beanDef = registry.getBeanDefinition(candidateName);
332 if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) &&
333 !alreadyParsedClasses.contains(beanDef.getBeanClassName())) {
334 configCandidates.add(new BeanDefinitionHolder(beanDef, candidateName));
335 }
336 }
337 }
338 candidateNames = newCandidateNames;
339 }
340 }
341 while (!configCandidates.isEmpty());
342
343
344 if (singletonRegistry != null) {
345 if (!singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
346 singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
347 }
348 }
349
350 if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
351 ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
352 }
353 }
354
355
356
357
358
359
360
361 public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
362 Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<String, AbstractBeanDefinition>();
363 for (String beanName : beanFactory.getBeanDefinitionNames()) {
364 BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
365 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
366 if (!(beanDef instanceof AbstractBeanDefinition)) {
367 throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
368 beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
369 }
370 configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
371 }
372 }
373 if (configBeanDefs.isEmpty()) {
374
375 return;
376 }
377 ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
378 for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
379 AbstractBeanDefinition beanDef = entry.getValue();
380
381 beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
382 try {
383
384 Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
385 Class<?> enhancedClass = enhancer.enhance(configClass);
386 if (configClass != enhancedClass) {
387 if (logger.isDebugEnabled()) {
388 logger.debug(String.format("Replacing bean definition '%s' existing class name '%s' " +
389 "with enhanced class name '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
390 }
391 beanDef.setBeanClass(enhancedClass);
392 }
393 }
394 catch (Throwable ex) {
395 throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
396 }
397 }
398 }
399
400
401 private static class ImportAwareBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware, PriorityOrdered {
402
403 private BeanFactory beanFactory;
404
405 @Override
406 public void setBeanFactory(BeanFactory beanFactory) {
407 this.beanFactory = beanFactory;
408 }
409
410 @Override
411 public int getOrder() {
412 return Ordered.HIGHEST_PRECEDENCE;
413 }
414
415 @Override
416 public Object postProcessBeforeInitialization(Object bean, String beanName) {
417 if (bean instanceof ImportAware) {
418 ImportRegistry importRegistry = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
419 AnnotationMetadata importingClass = importRegistry.getImportingClassFor(bean.getClass().getSuperclass().getName());
420 if (importingClass != null) {
421 ((ImportAware) bean).setImportMetadata(importingClass);
422 }
423 }
424 return bean;
425 }
426
427 @Override
428 public Object postProcessAfterInitialization(Object bean, String beanName) {
429 return bean;
430 }
431 }
432
433
434
435
436
437
438
439 private static class EnhancedConfigurationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
440 implements PriorityOrdered, BeanFactoryAware {
441
442 private BeanFactory beanFactory;
443
444 @Override
445 public int getOrder() {
446 return Ordered.HIGHEST_PRECEDENCE;
447 }
448
449 @Override
450 public void setBeanFactory(BeanFactory beanFactory) {
451 this.beanFactory = beanFactory;
452 }
453
454 @Override
455 public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
456
457
458 if (bean instanceof EnhancedConfiguration) {
459 ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
460 }
461 return pvs;
462 }
463 }
464
465 }