![](https://img.haomeiwen.com/i27938870/4af9df53e208fc4e.png)
SpringBoot自动配置原理是什么?
面试过程中问得最多的可能是自动装配的原理,而自动装配是在启动过程中完成,只不过在刚开始的时候我们选择性的跳过了,下面详细讲解自动装配的过程。
1、在springboot的启动过程中,有一个步骤是创建上下文,如果不记得可以看下面的代码:
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方法,一层一层向内点击,找到最终的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、实际执行load的是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注解,但是会神奇的发现我们的启动类中并没有该注解,继续更进发现MergedAnnotations类传入了一个参数
SearchStrategy.TYPE_HIERARCHY,会查找继承关系中是否包含这个注解,@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对象,从注解中找到相关的元数据
*/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.
* 注册主类,如果有别名可以设置别名
*/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的实例化和执行
/**
* Instantiate and invoke all registered BeanFactoryPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before singleton instantiation.
*/protectedvoidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory){//开始执行beanFactoryPostProcessor对应实现类,需要知道的是beanFactoryPostProcessor是spring的扩展接口,在刷新容器之前,该接口可以用来修改bean元数据信息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的具体执行方法
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<>();//开始遍历三个内部类,如果属于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获取到对应的处理类“org.springframework.context.annotation.internalConfigurationAnnotationProcessor”,但是需要注意的是这个类在springboot中搜索不到,这个类的完全限定名在AnnotationConfigEmbeddedWebApplicationContext中,在进行初始化的时候会装配几个类,在创建AnnotatedBeanDefinitionReader对象的时候会将该类注册到bean对象中,此处可以看到internalConfigurationAnnotationProcessor为bean名称,容器中真正的类是ConfigurationClassPostProcessorString[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,true,false);//首先执行类型为PriorityOrdered的BeanDefinitionRegistryPostProcessor//PriorityOrdered类型表明为优先执行for(String ppName : postProcessorNames) {if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)){//获取对应的beancurrentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));//用来存储已经执行过的BeanDefinitionRegistryPostProcessorprocessedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors);//开始执行装配逻辑invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.//其次执行类型为Ordered的BeanDefinitionRegistryPostProcessor//Ordered表明按顺序执行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.//循环中执行类型不为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. //执行父类方法,优先执行注册处理类invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);//执行有规则处理类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、开始执行自动配置逻辑(启动类指定的配置,非默认配置),可以通过debug的方式一层层向里进行查找,会发现最终会在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); } }//执行配置类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{//循环处理bean,如果有父类,则处理父类,直至结束sourceClass = doProcessConfigurationClass(configClass, sourceClass); }while(sourceClass !=null);this.configurationClasses.put(configClass, configClass); }
10、继续跟进
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 {//处理内部类逻辑,由于传来的参数是启动类,并不包含内部类,所以跳过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// 这里是根据启动类@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//递归解析,获取导入的配置类,很多情况下,导入的配置类中会同样包含导入类注解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//如果该类有父类,则继续返回,上层方法判断不为空,则继续递归执行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都以导入的方式被加载进去 */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、继续回到ConfigurationClassParser中的parse方法中的最后一行,继续跟进该方法:
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框架进行开发的时候,如果需要引入mybatis框架,那么需要在xml中定义需要的bean对象,这个过程很明显是很麻烦的,如果需要引入额外的其他组件,那么也需要进行复杂的配置,因此在springboot中引入了starter
starter就是一个jar包,写一个@Configuration的配置类,将这些bean定义在其中,然后再starter包的META-INF/spring.factories中写入配置类,那么springboot程序在启动的时候就会按照约定来加载该配置类
开发人员只需要将相应的starter包依赖进应用中,进行相关的属性配置,就可以进行代码开发,而不需要单独进行bean对象的配置
网友评论