注意:下面我使用了@Component,但其实它并不会因为这个注解初始化,因为我的扫描包路径是com.zzq.core。 之所以加@Component,是老版本要加Component、Bean、Configuration其一注解,或者派生,我用的是Spring 3.2.18的源码 registerBeanDefinitionForImportedConfigurationClass方法中ConfigurationClassUtils.checkConfigurationClassCandidate在检查 ,否则异常 Configuration problem: com.zzq.core.annotationdrivendevelopment.WebLogAspect was @Import’ed but is not annotated with @Configuration nor does it declare any @Bean methods; it does not implement ImportSelector or extend ImportBeanDefinitionRegistrar. Update the class to meet one of these requirements or do not attempt to @Import it. 我看了高版本的代码如 5.1.16.RELEASE没有这个限制,不用加注解
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
RootBeanDefinition iabpp = new RootBeanDefinition(ImportAwareBeanPostProcessor.class);
iabpp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME, iabpp);
//取得registry的id并做判重处理或记录
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called for this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called for this post-processor against " + registry);
}
//保存处理过的registry,避免重复处理
this.registriesPostProcessed.add(registryId);
//处理java配置形式的bean定义
processConfigBeanDefinitions(registry);
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
AnnotationMetadata metadata = configClass.getMetadata();
if (this.environment != null && metadata.isAnnotated(Profile.class.getName())) {
AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
if (!this.environment.acceptsProfiles(profile.getStringArray("value"))) {
return;
}
}
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
for (Iterator it = this.knownSuperclasses.values().iterator(); it.hasNext();) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
// Recursively process the configuration class and its superclass hierarchy.
do {
// 处理Bean
metadata = doProcessConfigurationClass(configClass, metadata);
}
while (metadata != null);
// 添加到集合中
this.configurationClasses.add(configClass);
}
protected AnnotationMetadata doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
// Recursively process any member (nested) classes first
processMemberClasses(metadata);
// Process any @PropertySource annotations
//处理@PropertySource 加载外面资源文件
AnnotationAttributes propertySource = MetadataUtils.attributesFor(metadata,
org.springframework.context.annotation.PropertySource.class);
if (propertySource != null) {
processPropertySource(propertySource);
}
// Process any @ComponentScan annotations
//处理 @ComponentScan 扫描包
AnnotationAttributes componentScan = MetadataUtils.attributesFor(metadata, ComponentScan.class);
if (componentScan != null) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, metadata.getClassName());
// scannedBeanDefinitions 有可能是空元素,因为在扫描包时会事先注册好
// Check the set of scanned definitions for any further config classes and parse recursively if necessary
// 如果有配置类,递归解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
}
//处理@Import注解
// Process any @Import annotations
Set
处理@Import注解
我们本章要关注的就是处理@Import注解部分
先收集导入的类collectImports
private void collectImports(AnnotationMetadata metadata, Set imports, Set visited) throws IOException {
String className = metadata.getClassName();
if (visited.add(className)) {
if (metadata instanceof StandardAnnotationMetadata) {
StandardAnnotationMetadata stdMetadata = (StandardAnnotationMetadata) metadata;
for (Annotation ann : stdMetadata.getIntrospectedClass().getAnnotations()) {
if (!ann.annotationType().getName().startsWith("java") && !(ann instanceof Import)) {
collectImports(new StandardAnnotationMetadata(ann.annotationType()), imports, visited);
}
}
//得到Import注解
Map attributes = stdMetadata.getAnnotationAttributes(Import.class.getName(), false);
if (attributes != null) {
Class>[] value = (Class>[]) attributes.get("value");
if (!ObjectUtils.isEmpty(value)) {
for (Class> importedClass : value) {
// Catch duplicate from ASM-based parsing...
imports.remove(importedClass.getName());
//把Import注解的值添加进去
imports.add(importedClass);
}
}
}
}
else {
for (String annotationType : metadata.getAnnotationTypes()) {
if (!className.startsWith("java") && !className.equals(Import.class.getName())) {
try {
collectImports(
new StandardAnnotationMetadata(this.resourceLoader.getClassLoader().loadClass(annotationType)),
imports, visited);
}
catch (ClassNotFoundException ex) {
// Silently ignore...
}
}
}
Map attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
if (attributes != null) {
String[] value = (String[]) attributes.get("value");
if (!ObjectUtils.isEmpty(value)) {
for (String importedClassName : value) {
// Catch duplicate from reflection-based parsing...
boolean alreadyThereAsClass = false;
for (Object existingImport : imports) {
if (existingImport instanceof Class &&
((Class>) existingImport).getName().equals(importedClassName)) {
alreadyThereAsClass = true;
}
}
if (!alreadyThereAsClass) {
imports.add(importedClassName);
}
}
}
}
}
}
}
找到要导入的类后,再进行处理processImport
private void processImport(ConfigurationClass configClass, AnnotationMetadata metadata,
Collection> classesToImport, boolean checkForCircularImports) throws IOException {
if (checkForCircularImports && this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
}
else {
this.importStack.push(configClass);
try {
for (Object candidate : classesToImport) {
Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
this.metadataReaderFactory.getMetadataReader((String) candidate));
//实现ImportSelector接口的处理
if (checkAssignability(ImportSelector.class, candidateToCheck)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
processImport(configClass, metadata, Arrays.asList(selector.selectImports(metadata)), false);
}
//实现ImportBeanDefinitionRegistrar接口的处理
else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar);
registrar.registerBeanDefinitions(metadata, this.registry);
}
else {
//候选类不是importSelector或importBeanDefinitionRegistrar
//@Configuration类的处理
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as a @Configuration class
this.importStack.registerImport(metadata,
(candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
processConfigurationClass(candidateToCheck instanceof Class ?
new ConfigurationClass((Class) candidateToCheck, true) :
new ConfigurationClass((MetadataReader) candidateToCheck, true));
}
}
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to load import candidate class", ex);
}
finally {
this.importStack.pop();
}
}
}
public void validate(ProblemReporter problemReporter) {
// A configuration class may not be final (CGLIB limitation)
if (getMetadata().isAnnotated(Configuration.class.getName())) {
if (getMetadata().isFinal()) {
problemReporter.error(new FinalConfigurationProblem());
}
}
// An @Bean method may only be overloaded through inheritance. No single
// @Configuration class may declare two @Bean methods with the same name.
Map methodNameCounts = new HashMap();
for (BeanMethod beanMethod : this.beanMethods) {
String fqMethodName = beanMethod.getFullyQualifiedMethodName();
Integer currentCount = methodNameCounts.get(fqMethodName);
int newCount = (currentCount != null ? currentCount + 1 : 1);
methodNameCounts.put(fqMethodName, newCount);
}
for (String fqMethodName : methodNameCounts.keySet()) {
int count = methodNameCounts.get(fqMethodName);
// 判断是否配置类方法名称重复,因为默认用方法名称作为beanName
if (count > 1) {
String shortMethodName = ConfigurationMethod.getShortMethodName(fqMethodName);
problemReporter.error(new BeanMethodOverloadingProblem(shortMethodName, count));
}
}
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
}
前面说的Configuration problem: com.zzq.core.annotationdrivendevelopment.WebLogAspect was @Import’ed but is not annotated with @Configuration nor does it declare any @Bean methods; it does not implement ImportSelector or extend ImportBeanDefinitionRegistrar. Update the class to meet one of these requirements or do not attempt to @Import it.异常就是在这个方法产生的
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
//判断是否 Component、Bean、Configuration其一注解,或者派生
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
this.registry.registerBeanDefinition(configBeanName, configBeanDef);
configClass.setBeanName(configBeanName);
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registered bean definition for imported @Configuration class %s", configBeanName));
}
}
else {
this.problemReporter.error(
new InvalidConfigurationImportProblem(metadata.getClassName(), configClass.getResource(), metadata));
}
}