spring的 @Bean @import 等都是注解式的配置,简化了通过xml形式的配置,它们是如何生效的?
注意@Componnet @Controller @Service @Repotory @configration 这几个配置类既可以在容器启动时通过ClassPathBeanDefinitionScanner指定包名扫描进容器; 也可以通过后置处理器在ComponentScanAnnotationParser配合@ComponnetScan注解指定包和属性在回调中扫描进容器。
chatgpt免费体验:http://www.chat136.com
chatgpt学习:http://me.chat136.com
而@Bean @import只能通过后置处理器实现bean的装载。ClassPathBeanDefinitionScanner只是装载有@Componnet注解的bean。
而由于@Controller @Service @Repotory @configration也是@Componnet的复合注解所以也可以通过scan方法中扫描注入。
@import不管普通类还是配置类都是通过后置处理器加到容器中。所以比如springboot中大量运用@import来加载 @configration和@bean的类。
1. Application构造函数
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
通过ConfigurationClassPostProcessor这个bean工厂后置处理器实现加载进spring的,ConfigurationClassPostProcessor是spring容器的底层组件实现了BeanFactoryPostProcessor接口注意不是BeanPostProcessor接口,这个接口的类在refresh方法容器的自定义bean初始化之前会被容器回调从而可以修改或增加bean定义, 是通过ApplicationContext构造函数时加载进容器的,下面看一下spring的源码从AnnotationConfigApplicationContext开始。
2. 上面this()无参构造函数会通过一系列调用链到这个方法org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
registerAnnotationConfigProcessors方法会注册spring底层的一些组件,包括前面实现自动扫描的ConfigurationClassPostProcessor这个后置处理器。
public static SetregisterAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); if (beanFactory != null) { if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) { beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); } if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) { beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); } } Set beanDefs = new LinkedHashSet<>(4); //这是注册ConfigurationClassPostProcessor进容器 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)); } // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor. if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(); try { def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader())); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex); } def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME)); } return beanDefs; }
3. 看一下AbstractApplictionContext的refresh方法
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.这里会回回调所有的 BeanFactoryPostProcess ,包括ConfigurationClassPostProcessor invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
4. 下面看一下ConfigurationClassPostProcessor具体是怎么实现基于注解的bean加载的
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 这个方法会被spring在refresh()里面自动回调
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { ListconfigCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames();//获取当前容器所有的bean的名称,这是bean还没初始化 for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName);//获取beanDeinition,包含bean的配置信息如注解,方法,构造函数,class信息都放在BeanDefinition里 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {//检查是否是配置bean即包含@Configration,@Componet @ComponentScan @Import @ImportSouce 注解(@Controller @Service注解式是@Component的复合注解),如果没有就跳过
if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {//包含配置注解放入待处理列表 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } // Return immediately if no @Configuration classes were found if (configCandidates.isEmpty()) {//待处理列表为空结束返回 return; } // Sort by previously determined @Order value, if applicable //根据类配置优先顺序排序 configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // Detect any custom bean name generation strategy supplied through the enclosing application context SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } if (this.environment == null) { this.environment = new StandardEnvironment(); } // Parse each @Configuration class //这个parse类重要,里面存有处理后生成的class信息,处理方法也封装进这个类里,这里传入上面configcadidates列表,这个类内部的方法处理完毕后,结果返回beandifiniton列表再加载进容器 ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Setcandidates = new LinkedHashSet<>(configCandidates); Set alreadyParsed = new HashSet<>(configCandidates.size()); do { parser.parse(candidates);//处理上面得到的canditates parser.validate();//验证 // 这个parser.getConfigurationClasses() 是返回处理后的配置类信息,即把@Configration @Componet @Bean等解析为一个个BeanDifition的基础信息 Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } this.reader.loadBeanDefinitions(configClasses);//把处理得到Bean定义信息装载进容器 alreadyParsed.addAll(configClasses); candidates.clear();//判断是否有新的类装进容器了,有就检查进行下个循环 if (registry.getBeanDefinitionCount() > candidateNames.length) {//这里的循环意思是每次装载完处理生成的bean定义信息后,重新检查容器是否还有待处理的配置类,因为上一次装载进容器的可能是新的配置类,比如a配置类在上一批次装载了b配置类进容器,a配置类已经处理完了,但新装载的b配置类还没处理过,要重新检查容器继续处理b配置类,直到素有的配置类处理完毕,就是所有包含@Configration @Component等的类都处理完成了 不会再加载新的类 String[] newCandidateNames = registry.getBeanDefinitionNames(); Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); Set alreadyParsedClasses = new HashSet<>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } for (String candidateName : newCandidateNames) { if (!oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {// 这里检查是否是配置类即包含@Configration @Component等注解 candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty()); // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { // Clear cache in externally provided MetadataReaderFactory; this is a no-op // for a shared cache since it'll be cleared by the ApplicationContext. ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); } }
5.下面看一下 parser.parse(candidates)这个方法是怎么实现的
该方法会调到这里,下面的几个方法都是在parser类里定义的。
public void parse(SetconfigCandidates) { this.deferredImportSelectors = new LinkedList<>(); //这个循环是逐个处理外面传进来的配置类信息 for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } processDeferredImportSelectors(); }
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName)); }
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//这里ConfigurationClass 是封装了上面待处理的配置类beandifinition信息
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {//这里sourceClass返回的待处理配置类的父类即循环递归处理父类信息
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
//这里是加入处理完成的配置类信息列表configurationClasse 这个列表是该类全局共享的属性,后面会返回给外部调用方
this.configurationClasses.put(configClass, configClass);
}
org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
@Nullable protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass);//递归处理处理成员内部类,里面回调外层的 processConfigurationClass方法。 // Process any @PropertySource annotations for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations SetcomponentScans = AnnotationConfigUtils. attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately //这里使用componnetScanParser扫描@Component注解直接装进容器,而componentScanParser内部使用的是ClassPathBeanDefinitionScanner类,该类构造函数指定扫描类型为@Component的bean, 再判断bean是否是配置类即如果含有是@Configration @Import等注解标注的配置类 递归调用parse方法。 SetscannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName());//这里递归处理扫描到的配置类 } } } } // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), true);//这里处理@import标签 // Process any @ImportResource annotations AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual @Bean methods SetbeanMethods = retrieveBeanMethodMetadata(sourceClass) ; for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces processInterfaces(configClass, sourceClass); // Process superclass, if any if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } //上面的这几个方法都是parser类里定义的,执行结束后 parser类里其实已经填充了处理后的信息,这里相当于设计模式解析器模式 // No superclass -> processing is complete return null; }
解析结束,下面是把bean定义载入进容器,从而实现基于注解的配置
SetconfigurationModel是parse类解析后得到的bean定义信息org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
public void loadBeanDefinitions(SetconfigurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); for (ConfigurationClass configClass : configurationModel) { loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); } }
/**
* Read a particular {@link ConfigurationClass}, registering bean definitions * for the class itself and all of its {@link Bean} methods. */ private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } if (configClass.isImported()) { //载入通过@import标签引入的bean registerBeanDefinitionForImportedConfigurationClass(configClass); } for (BeanMethod beanMethod : configClass.getBeanMethods()) { //载入通过通过@bean方式引入的bean loadBeanDefinitionsForBeanMethod(beanMethod); } //载入@importResources loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); // 这个也是@import loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
至此@bean配置类装载进了容器。