SpringBoot自動配置原理是什么?
面試過程中問得最多的可能是自動裝配的原理卑笨,而自動裝配是在啟動過程中完成孕暇,只不過在剛開始的時候我們選擇性的跳過了,下面詳細講解自動裝配的過程赤兴。
1妖滔、在springboot的啟動過程中,有一個步驟是創(chuàng)建上下文桶良,如果不記得可以看下面的代碼:
public ConfigurableApplicationContext run(String... args) {? ? ? ? StopWatch stopWatch =newStopWatch();? ? ? ? stopWatch.start();? ? ? ? ConfigurableApplicationContext context =null;? ? ? ? Collection exceptionReporters =newArrayList<>();? ? ? ? configureHeadlessProperty();? ? ? ? SpringApplicationRunListeners listeners = getRunListeners(args);? ? ? ? listeners.starting();try{? ? ? ? ? ? ApplicationArguments applicationArguments =newDefaultApplicationArguments(args);? ? ? ? ? ? ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);? ? ? ? ? ? configureIgnoreBeanInfo(environment);? ? ? ? ? ? Banner printedBanner = printBanner(environment);? ? ? ? ? ? context = createApplicationContext();? ? ? ? ? ? exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,newClass[] { ConfigurableApplicationContext.class},context);//此處完成自動裝配的過程? ? ? ? ? ? prepareContext(context, environment, listeners, applicationArguments, printedBanner);? ? ? ? ? ? refreshContext(context);? ? ? ? ? ? afterRefresh(context, applicationArguments);? ? ? ? ? ? stopWatch.stop();if(this.logStartupInfo) {newStartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);? ? ? ? ? ? }? ? ? ? ? ? listeners.started(context);? ? ? ? ? ? callRunners(context, applicationArguments);? ? ? ? }catch(Throwable ex) {? ? ? ? ? ? handleRunFailure(context, ex, exceptionReporters, listeners);thrownewIllegalStateException(ex);? ? ? ? }try{? ? ? ? ? ? listeners.running(context);? ? ? ? }catch(Throwable ex) {? ? ? ? ? ? handleRunFailure(context, ex, exceptionReporters,null);thrownewIllegalStateException(ex);? ? ? ? }returncontext;? ? }
2座舍、在prepareContext方法中查找load方法,一層一層向內(nèi)點擊陨帆,找到最終的load方法
//prepareContext方法privatevoid prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,? ? ? ? ? ? SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {? ? ? ? context.setEnvironment(environment);? ? ? ? postProcessApplicationContext(context);? ? ? ? applyInitializers(context);? ? ? ? listeners.contextPrepared(context);if(this.logStartupInfo) {? ? ? ? ? ? logStartupInfo(context.getParent() ==null);? ? ? ? ? ? logStartupProfileInfo(context);? ? ? ? }// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();? ? ? ? beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if(printedBanner !=null) {? ? ? ? ? ? beanFactory.registerSingleton("springBootBanner", printedBanner);? ? ? ? }if(beanFactory instanceof DefaultListableBeanFactory) {? ? ? ? ? ? ((DefaultListableBeanFactory) beanFactory)? ? ? ? ? ? ? ? ? ? .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);? ? ? ? }if(this.lazyInitialization) {? ? ? ? ? ? context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());? ? ? ? }// Load the sourcesSet sources = getAllSources();? ? ? ? Assert.notEmpty(sources,"Sources must not be empty");//load方法完成該功能load(context, sources.toArray(new Object[0]));? ? ? ? listeners.contextLoaded(context);? ? }/**? ? * Load beans into the application context.? ? *@paramcontext the context to load beans into? ? *@paramsources the sources to load? ? * 加載bean對象到context中? ? */protectedvoid load(ApplicationContext context, Object[] sources) {if(logger.isDebugEnabled()) {? ? ? ? ? ? logger.debug("Loading source "+ StringUtils.arrayToCommaDelimitedString(sources));? ? ? ? }//獲取bean對象定義的加載器BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);if(this.beanNameGenerator !=null) {? ? ? ? ? ? loader.setBeanNameGenerator(this.beanNameGenerator);? ? ? ? }if(this.resourceLoader !=null) {? ? ? ? ? ? loader.setResourceLoader(this.resourceLoader);? ? ? ? }if(this.environment !=null) {? ? ? ? ? ? loader.setEnvironment(this.environment);? ? ? ? }? ? ? ? loader.load();? ? }/**? ? * Load the sources into the reader.? ? *@returnthe number of loaded beans? ? */int load() {? ? ? ? int count =0;for(Object source :this.sources) {? ? ? ? ? ? count += load(source);? ? ? ? }returncount;? ? }
3曲秉、實際執(zhí)行l(wèi)oad的是BeanDefinitionLoader中的load方法,如下:
//實際記載bean的方法privateintload(Object source){? ? ? ? Assert.notNull(source,"Source must not be null");//如果是class類型疲牵,啟用注解類型if(sourceinstanceofClass) {returnload((Class) source);? ? ? ? }//如果是resource類型承二,啟動xml解析if(sourceinstanceofResource) {returnload((Resource) source);? ? ? ? }//如果是package類型,啟用掃描包纲爸,例如@ComponentScanif(sourceinstanceofPackage) {returnload((Package) source);? ? ? ? }//如果是字符串類型亥鸠,直接加載if(sourceinstanceofCharSequence) {returnload((CharSequence) source);? ? ? ? }thrownewIllegalArgumentException("Invalid source type "+ source.getClass());? ? }
4、下面方法將用來判斷是否資源的類型,是使用groovy加載還是使用注解的方式
privateint load(Class source) {//判斷使用groovy腳本if(isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {// Any GroovyLoaders added in beans{} DSL can contribute beans hereGroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);load(loader);? ? ? ? }//使用注解加載if(isComponent(source)) {this.annotatedReader.register(source);return1;? ? ? ? }return0;? ? }
5负蚊、下面方法判斷啟動類中是否包含@Component注解神妹,但是會神奇的發(fā)現(xiàn)我們的啟動類中并沒有該注解,繼續(xù)更進發(fā)現(xiàn)MergedAnnotations類傳入了一個參數(shù)
SearchStrategy.TYPE_HIERARCHY家妆,會查找繼承關(guān)系中是否包含這個注解鸵荠,@SpringBootApplication-->@SpringBootConfiguration-->@Configuration-->@Component,當找到@Component注解之后,會把該對象注冊到AnnotatedBeanDefinitionReader對象中
privatebooleanisComponent(Classtype) {// This has to be a bit of a guess. The only way to be sure that this type is// eligible is to make a bean definition out of it and try to instantiate it.if(MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class)) {returntrue;? }// Nested anonymous classes are not eligible for registration, nor are groovy// closuresreturn!type.getName().matches(".*\\$_.*closure.*") && !type.isAnonymousClass()? ? ? ? &&type.getConstructors() !=null&&type.getConstructors().length !=0;}/**
? ? * Register a bean from the given bean class, deriving its metadata from
? ? * class-declared annotations.
? ? * 從給定的bean class中注冊一個bean對象伤极,從注解中找到相關(guān)的元數(shù)據(jù)
? ? */privatevoiddoRegisterBean(Class beanClass,@NullableStringname,@NullableClass[] qualifiers,@NullableSupplier supplier,@NullableBeanDefinitionCustomizer[] customizers) {? ? ? ? AnnotatedGenericBeanDefinition abd =newAnnotatedGenericBeanDefinition(beanClass);if(this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;? ? ? ? }? ? ? ? abd.setInstanceSupplier(supplier);? ? ? ? ScopeMetadata scopeMetadata =this.scopeMetadataResolver.resolveScopeMetadata(abd);? ? ? ? abd.setScope(scopeMetadata.getScopeName());StringbeanName = (name !=null? name :this.beanNameGenerator.generateBeanName(abd,this.registry));? ? ? ? AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if(qualifiers !=null) {for(Class qualifier : qualifiers) {if(Primary.class == qualifier) {? ? ? ? ? ? ? ? ? ? abd.setPrimary(true);? ? ? ? ? ? ? ? }elseif(Lazy.class == qualifier) {? ? ? ? ? ? ? ? ? ? abd.setLazyInit(true);? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? abd.addQualifier(newAutowireCandidateQualifier(qualifier));? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }if(customizers !=null) {for(BeanDefinitionCustomizer customizer : customizers) {? ? ? ? ? ? ? ? customizer.customize(abd);? ? ? ? ? ? }? ? ? ? }? ? ? ? BeanDefinitionHolder definitionHolder =newBeanDefinitionHolder(abd, beanName);? ? ? ? definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder,this.registry);? ? ? ? BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder,this.registry);? ? }/**
? ? * Register the given bean definition with the given bean factory.
? ? * 注冊主類蛹找,如果有別名可以設(shè)置別名
? ? */publicstaticvoidregisterBeanDefinition(? ? ? ? ? ? BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)? ? ? ? ? ? throws BeanDefinitionStoreException {// Register bean definition under primary name.StringbeanName = definitionHolder.getBeanName();? ? ? ? registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// Register aliases for bean name, if any.String[] aliases = definitionHolder.getAliases();if(aliases !=null) {for(Stringalias : aliases) {? ? ? ? ? ? ? ? registry.registerAlias(beanName, alias);? ? ? ? ? ? }? ? ? ? }? ? }//@SpringBootApplication@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = {@Filter(type= FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type= FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public@interfaceSpringBootApplication {}//@SpringBootConfiguration@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic@interfaceSpringBootConfiguration {}//@Configuration@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic@interfaceConfiguration {}
當看完上述代碼之后,只是完成了啟動對象的注入塑荒,自動裝配還沒有開始熄赡,下面開始進入到自動裝配。
6齿税、自動裝配入口彼硫,從刷新容器開始
@Overridepublicvoidrefresh()throwsBeansException, 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.// 此處是自動裝配的入口invokeBeanFactoryPostProcessors(beanFactory);? ? ? ? ? ? }
7、在
invokeBeanFactoryPostProcessors方法中完成bean的實例化和執(zhí)行
/**
? ? * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
? ? * respecting explicit order if given.
? ? * <p>Must be called before singleton instantiation.
? ? */protectedvoidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory){//開始執(zhí)行beanFactoryPostProcessor對應(yīng)實現(xiàn)類,需要知道的是beanFactoryPostProcessor是spring的擴展接口凌箕,在刷新容器之前拧篮,該接口可以用來修改bean元數(shù)據(jù)信息PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)if(beanFactory.getTempClassLoader() ==null&& beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {? ? ? ? ? ? beanFactory.addBeanPostProcessor(newLoadTimeWeaverAwareProcessor(beanFactory));? ? ? ? ? ? beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));? ? ? ? }? ? }
8、查看
invokeBeanFactoryPostProcessors的具體執(zhí)行方法
publicstaticvoidinvokeBeanFactoryPostProcessors(
? ? ? ? ? ? ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors){// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set processedBeans =newHashSet<>();if(beanFactoryinstanceofBeanDefinitionRegistry) {? ? ? ? ? ? BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;? ? ? ? ? ? List regularPostProcessors =newArrayList<>();? ? ? ? ? ? List registryProcessors =newArrayList<>();//開始遍歷三個內(nèi)部類牵舱,如果屬于BeanDefinitionRegistryPostProcessor子類串绩,加入到bean注冊的集合,否則加入到regularPostProcessorsfor(BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if(postProcessorinstanceofBeanDefinitionRegistryPostProcessor) {? ? ? ? ? ? ? ? ? ? BeanDefinitionRegistryPostProcessor registryProcessor =? ? ? ? ? ? ? ? ? ? ? ? ? ? (BeanDefinitionRegistryPostProcessor) postProcessor;? ? ? ? ? ? ? ? ? ? registryProcessor.postProcessBeanDefinitionRegistry(registry);? ? ? ? ? ? ? ? ? ? registryProcessors.add(registryProcessor);? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? regularPostProcessors.add(postProcessor);? ? ? ? ? ? ? ? }? ? ? ? ? ? }// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List currentRegistryProcessors =newArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.//通過BeanDefinitionRegistryPostProcessor獲取到對應(yīng)的處理類“org.springframework.context.annotation.internalConfigurationAnnotationProcessor”芜壁,但是需要注意的是這個類在springboot中搜索不到礁凡,這個類的完全限定名在AnnotationConfigEmbeddedWebApplicationContext中,在進行初始化的時候會裝配幾個類慧妄,在創(chuàng)建AnnotatedBeanDefinitionReader對象的時候會將該類注冊到bean對象中顷牌,此處可以看到internalConfigurationAnnotationProcessor為bean名稱,容器中真正的類是ConfigurationClassPostProcessorString[] postProcessorNames =? ? ? ? ? ? ? ? ? ? beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,true,false);//首先執(zhí)行類型為PriorityOrdered的BeanDefinitionRegistryPostProcessor//PriorityOrdered類型表明為優(yōu)先執(zhí)行for(String ppName : postProcessorNames) {if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)){//獲取對應(yīng)的beancurrentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));//用來存儲已經(jīng)執(zhí)行過的BeanDefinitionRegistryPostProcessorprocessedBeans.add(ppName);? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? ? ? sortPostProcessors(currentRegistryProcessors, beanFactory);? ? ? ? ? ? registryProcessors.addAll(currentRegistryProcessors);//開始執(zhí)行裝配邏輯invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);? ? ? ? ? ? currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.//其次執(zhí)行類型為Ordered的BeanDefinitionRegistryPostProcessor//Ordered表明按順序執(zhí)行postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,true,false);for(String ppName : postProcessorNames) {if(!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)){? ? ? ? ? ? ? ? ? ? currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));? ? ? ? ? ? ? ? ? ? processedBeans.add(ppName);? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? ? ? sortPostProcessors(currentRegistryProcessors, beanFactory);? ? ? ? ? ? registryProcessors.addAll(currentRegistryProcessors);? ? ? ? ? ? invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);? ? ? ? ? ? currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.//循環(huán)中執(zhí)行類型不為PriorityOrdered塞淹,Ordered類型的BeanDefinitionRegistryPostProcessorbooleanreiterate =true;while(reiterate) {? ? ? ? ? ? ? ? reiterate =false;? ? ? ? ? ? ? ? postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,true,false);for(String ppName : postProcessorNames) {if(!processedBeans.contains(ppName)) {? ? ? ? ? ? ? ? ? ? ? ? currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));? ? ? ? ? ? ? ? ? ? ? ? processedBeans.add(ppName);? ? ? ? ? ? ? ? ? ? ? ? reiterate =true;? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? sortPostProcessors(currentRegistryProcessors, beanFactory);? ? ? ? ? ? ? ? registryProcessors.addAll(currentRegistryProcessors);? ? ? ? ? ? ? ? invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);? ? ? ? ? ? ? ? currentRegistryProcessors.clear();? ? ? ? ? ? }// Now, invoke the postProcessBeanFactory callback of all processors handled so far.? ? //執(zhí)行父類方法窟蓝,優(yōu)先執(zhí)行注冊處理類invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);//執(zhí)行有規(guī)則處理類invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);? ? ? ? }else{// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);? ? ? ? }// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =? ? ? ? ? ? ? ? beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class,true,false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List priorityOrderedPostProcessors =newArrayList<>();? ? ? ? List orderedPostProcessorNames =newArrayList<>();? ? ? ? List nonOrderedPostProcessorNames =newArrayList<>();for(String ppName : postProcessorNames) {if(processedBeans.contains(ppName)) {// skip - already processed in first phase above}elseif(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)){? ? ? ? ? ? ? ? priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));? ? ? ? ? ? }elseif(beanFactory.isTypeMatch(ppName, Ordered.class)){? ? ? ? ? ? ? ? orderedPostProcessorNames.add(ppName);? ? ? ? ? ? }else{? ? ? ? ? ? ? ? nonOrderedPostProcessorNames.add(ppName);? ? ? ? ? ? }? ? ? ? }// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);? ? ? ? invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List orderedPostProcessors =newArrayList<>(orderedPostProcessorNames.size());for(String postProcessorName : orderedPostProcessorNames) {? ? ? ? ? ? orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));? ? ? ? }? ? ? ? sortPostProcessors(orderedPostProcessors, beanFactory);? ? ? ? invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List nonOrderedPostProcessors =newArrayList<>(nonOrderedPostProcessorNames.size());for(String postProcessorName : nonOrderedPostProcessorNames) {? ? ? ? ? ? nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));? ? ? ? }? ? ? ? invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();? ? }
9、開始執(zhí)行自動配置邏輯(啟動類指定的配置饱普,非默認配置)运挫,可以通過debug的方式一層層向里進行查找,會發(fā)現(xiàn)最終會在ConfigurationClassParser類中套耕,此類是所有配置類的解析類谁帕,所有的解析邏輯在parser.parse(candidates)中
publicvoidparse(Set<BeanDefinitionHolder> configCandidates){for(BeanDefinitionHolder holder : configCandidates) {? ? ? ? ? ? BeanDefinition bd = holder.getBeanDefinition();try{//是否是注解類if(bdinstanceofAnnotatedBeanDefinition) {? ? ? ? ? ? ? ? ? ? parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());? ? ? ? ? ? ? ? }elseif(bdinstanceofAbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {? ? ? ? ? ? ? ? ? ? parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? parse(bd.getBeanClassName(), holder.getBeanName());? ? ? ? ? ? ? ? }? ? ? ? ? ? }catch(BeanDefinitionStoreException ex) {throwex;? ? ? ? ? ? }catch(Throwable ex) {thrownewBeanDefinitionStoreException("Failed to parse configuration class ["+ bd.getBeanClassName() +"]", ex);? ? ? ? ? ? }? ? ? ? }//執(zhí)行配置類this.deferredImportSelectorHandler.process();? ? }-------------------protectedfinalvoidparse(AnnotationMetadata metadata, String beanName)throwsIOException{? ? ? ? processConfigurationClass(newConfigurationClass(metadata, beanName));? ? }-------------------protectedvoidprocessConfigurationClass(ConfigurationClass configClass)throwsIOException{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{//循環(huán)處理bean,如果有父類,則處理父類冯袍,直至結(jié)束sourceClass = doProcessConfigurationClass(configClass, sourceClass);? ? ? ? }while(sourceClass !=null);this.configurationClasses.put(configClass, configClass);? ? }
10雇卷、繼續(xù)跟進
doProcessConfigurationClass方法,此方式是支持注解配置的核心邏輯
/**? ? * Apply processing and build a complete {@linkConfigurationClass} by reading the? ? * annotations, members and methods from the source class. This method can be called? ? * multiple times as relevant sources are discovered.? ? *@paramconfigClass the configuration class being build? ? *@paramsourceClass a source class? ? *@returnthe superclass, or {@codenull} if none found or previously processed? ? */@NullableprotectedfinalSourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)? ? ? ? ? ? throws IOException {//處理內(nèi)部類邏輯,由于傳來的參數(shù)是啟動類关划,并不包含內(nèi)部類,所以跳過if(configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass);? ? ? ? }// 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.info("Ignoring @PropertySource annotation on ["+ sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");? ? ? ? ? ? }? ? ? ? }// Process any @ComponentScan annotations// 這里是根據(jù)啟動類@ComponentScan注解來掃描項目中的beanSet componentScans = 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//遍歷項目中的bean翘瓮,如果是注解定義的bean贮折,則進一步解析Set scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor(BeanDefinitionHolder holder : scannedBeanDefinitions) {? ? ? ? ? ? ? ? ? ? BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if(bdCand ==null) {? ? ? ? ? ? ? ? ? ? ? ? bdCand = holder.getBeanDefinition();? ? ? ? ? ? ? ? ? ? }if(ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand,this.metadataReaderFactory)) {//遞歸解析,所有的bean,如果有注解资盅,會進一步解析注解中包含的beanparse(bdCand.getBeanClassName(), holder.getBeanName());? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }// Process any @Import annotations//遞歸解析调榄,獲取導(dǎo)入的配置類,很多情況下呵扛,導(dǎo)入的配置類中會同樣包含導(dǎo)入類注解processImports(configClass, sourceClass, getImports(sourceClass),true);// Process any @ImportResource annotations//解析@ImportResource配置類AnnotationAttributes importResource =? ? ? ? ? ? ? ? AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if(importResource !=null) {? ? ? ? ? ? String[] resources = importResource.getStringArray("locations");? ? ? ? ? ? Class readerClass = importResource.getClass("reader");for(String resource : resources) {? ? ? ? ? ? ? ? String resolvedResource =this.environment.resolveRequiredPlaceholders(resource);? ? ? ? ? ? ? ? configClass.addImportedResource(resolvedResource, readerClass);? ? ? ? ? ? }? ? ? ? }// Process individual @Bean methods//處理@Bean注解修飾的類Set beanMethods = retrieveBeanMethodMetadata(sourceClass);for(MethodMetadata methodMetadata : beanMethods) {? ? ? ? ? ? configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));? ? ? ? }// Process default methods on interfaces// 處理接口中的默認方法processInterfaces(configClass, sourceClass);// Process superclass, if any//如果該類有父類每庆,則繼續(xù)返回,上層方法判斷不為空今穿,則繼續(xù)遞歸執(zhí)行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 recursereturnsourceClass.getSuperClass();? ? ? ? ? ? }? ? ? ? }// No superclass -> processing is completereturnnull;? ? }
11缤灵、查看獲取配置類的邏輯
processImports(configClass, sourceClass, getImports(sourceClass),true);/**? ? * Returns {@code@Import} class, considering all meta-annotations.? ? */privateSet getImports(SourceClass sourceClass) throws IOException {? ? ? ? Set imports = new LinkedHashSet<>();? ? ? ? Set visited = new LinkedHashSet<>();? ? ? ? collectImports(sourceClass, imports, visited);returnimports;? ? }------------------/**? ? * Recursively collect all declared {@code@Import} values. Unlike most? ? * meta-annotations it is valid to have several {@code@Import}s declared with? ? * different values; the usual process of returning values from the first? ? * meta-annotation on a class is not sufficient.? ? *
For example, it is common for a {@code@Configuration} class to declare direct? ? * {@code@Import}s in addition to meta-imports originating from an {@code@Enable}? ? * annotation.? ? * 看到所有的bean都以導(dǎo)入的方式被加載進去? ? */privatevoid collectImports(SourceClass sourceClass, Set imports, Set visited)? ? ? ? ? ? throws IOException {if(visited.add(sourceClass)) {for(SourceClassannotation: sourceClass.getAnnotations()) {? ? ? ? ? ? ? ? String annName =annotation.getMetadata().getClassName();if(!annName.equals(Import.class.getName())) {? ? ? ? ? ? ? ? ? ? collectImports(annotation, imports, visited);? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? ? ? imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(),"value"));? ? ? ? }? ? }
12、繼續(xù)回到ConfigurationClassParser中的parse方法中的最后一行,繼續(xù)跟進該方法:
this.deferredImportSelectorHandler.process()-------------publicvoid process() {? ? ? ? ? ? List deferredImports =this.deferredImportSelectors;this.deferredImportSelectors =null;try{if(deferredImports !=null) {? ? ? ? ? ? ? ? ? ? DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();? ? ? ? ? ? ? ? ? ? deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);? ? ? ? ? ? ? ? ? ? deferredImports.forEach(handler::register);? ? ? ? ? ? ? ? ? ? handler.processGroupImports();? ? ? ? ? ? ? ? }? ? ? ? ? ? }finally{this.deferredImportSelectors = new ArrayList<>();? ? ? ? ? ? }? ? ? ? }---------------publicvoid processGroupImports() {for(DeferredImportSelectorGrouping grouping :this.groupings.values()) {? ? ? ? ? ? ? ? grouping.getImports().forEach(entry -> {? ? ? ? ? ? ? ? ? ? ConfigurationClass configurationClass =this.configurationClasses.get(? ? ? ? ? ? ? ? ? ? ? ? ? ? entry.getMetadata());try{? ? ? ? ? ? ? ? ? ? ? ? processImports(configurationClass, asSourceClass(configurationClass),? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? asSourceClasses(entry.getImportClassName()),false);? ? ? ? ? ? ? ? ? ? }catch(BeanDefinitionStoreException ex) {throwex;? ? ? ? ? ? ? ? ? ? }catch(Throwable ex) {thrownew BeanDefinitionStoreException("Failed to process import candidates for configuration class ["+? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? configurationClass.getMetadata().getClassName() +"]", ex);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? });? ? ? ? ? ? }? ? ? ? }------------/**? ? ? ? * Return the imports defined by the group.? ? ? ? *@returneach import with its associated configuration class? ? ? ? */publicIterable getImports() {for(DeferredImportSelectorHolder deferredImport :this.deferredImports) {this.group.process(deferredImport.getConfigurationClass().getMetadata(),? ? ? ? ? ? ? ? ? ? ? ? deferredImport.getImportSelector());? ? ? ? ? ? }returnthis.group.selectImports();? ? ? ? }? ? }------------publicDeferredImportSelector getImportSelector() {returnthis.importSelector;? ? ? ? }------------@Overridepublicvoid process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {? ? ? ? ? ? Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,? ? ? ? ? ? ? ? ? ? () -> String.format("Only %s implementations are supported, got %s",? ? ? ? ? ? ? ? ? ? ? ? ? ? AutoConfigurationImportSelector.class.getSimpleName(),? ? ? ? ? ? ? ? ? ? ? ? ? ? deferredImportSelector.getClass().getName()));? ? ? ? ? ? AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)? ? ? ? ? ? ? ? ? ? .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);this.autoConfigurationEntries.add(autoConfigurationEntry);for(String importClassName : autoConfigurationEntry.getConfigurations()) {this.entries.putIfAbsent(importClassName, annotationMetadata);? ? ? ? ? ? }? ? ? ? }
如何理解springboot中的starter蓝晒?
使用spring+springmvc框架進行開發(fā)的時候腮出,如果需要引入mybatis框架,那么需要在xml中定義需要的bean對象芝薇,這個過程很明顯是很麻煩的胚嘲,如果需要引入額外的其他組件,那么也需要進行復(fù)雜的配置洛二,因此在springboot中引入了starter
starter就是一個jar包馋劈,寫一個@Configuration的配置類,將這些bean定義在其中晾嘶,然后再starter包的META-INF/spring.factories中寫入配置類妓雾,那么springboot程序在啟動的時候就會按照約定來加載該配置類
開發(fā)人員只需要將相應(yīng)的starter包依賴進應(yīng)用中,進行相關(guān)的屬性配置变擒,就可以進行代碼開發(fā)君珠,而不需要單獨進行bean對象的配置