Heim >Java >javaLernprogramm >Was ist der SpringBoot-Startcode und der Quellcode für die automatische Assemblierung?
Mit der rasanten Entwicklung des Internets tauchen endlos verschiedene Komponenten auf und immer mehr Komponenten erfordern eine Framework-Integration. Jede Komponente muss relevanten Code implementieren, um in den Spring-Container integriert zu werden. Die Konfiguration des SpringMVC-Frameworks ist zu umständlich und basiert auf XML-Dateien. Um die schnelle Integration von Komponenten von Drittanbietern zu erleichtern und die Abhängigkeit von Konfigurationsdateien zu verringern, wurde SpringBoot ins Leben gerufen, das die Theorie der Konvention über die Konfiguration übernimmt, sodass Entwickler dies nicht benötigen zu viel für die Entwicklung konfigurieren. Spring, das am Ende von SpringBoot verwendet wird, integriert standardmäßig die automatische Montage von N mehreren Komponenten. Die Verwendung von SpringBoot ist einfach: Fügen Sie eine @SpringBootApplication zur Hauptklasse hinzu, rufen Sie SpringApplication.run() auf und übergeben Sie die Hauptklasse. Der Code lautet wie folgt
@SpringBootApplication public class StartApp { public static void main(String[] args) { SpringApplication.run(StartApp.class); } }
Aus dem obigen Quellcode können wir sehen, dass SpringApplication.run() der Programmeingang von SpringBoot ist. In diesem Artikel wird es unter zwei Aspekten analysiert: SpringApplication.run() und @SpringBootApplication-Annotation.
Erstellen Sie im Schlüsselcode von SpringApplication.run (StartApp.class) zunächst eine SpringApplication-Klasse und führen Sie dann die Ausführungsmethode aus. Der Code lautet wie folgt:
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
1 Der Konstruktionsmethodencode von SpringApplication lautet wie folgt
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // 设置资源加载器 this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // 设置应用主配置类 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 获取web服务器类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 从spring.factories 文件中获取 ApplicationContextInitializer 的实现类 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 从spring.factories 文件中获取 ApplicationListener 监听器的实现类 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 设置main启动类 this.mainApplicationClass = deduceMainApplicationClass(); }
Die Hauptlogik in der Konstruktionsmethode:
#🎜🎜 #1. Legen Sie die Hauptkonfigurationsklasse der Anwendung fest, die in der nachfolgenden Ausführungsmethode verwendet wird, um sie in einen BeanDefinitionHolder zu kapseln und in die Registrierung des Kontexts zu laden. 2. Rufen Sie den Webservertyp ab, der in der späteren Ausführungsmethode zum Erstellen eines bestimmten Webdiensttyps verwendet wird. 3. Holen Sie sich die Implementierungsklasse von ApplicationContextInitializer aus der spring.factories-Datei und legen Sie sie auf die SpringApplication-Instanz fest. 4. Holen Sie sich die Implementierungsklasse des ApplicationListener-Listeners aus dem Spring .factories-Datei und legen Sie sie auf die SpringApplication-Instanz fest Schnittstelle aus der Klassenzeichenfolge der Datei META-INF/spring.factories und instanziieren Sie die Zeichenfolge in ein Objekt. Der Code lautet wie folgt:// 获取类加载器 ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates // 根据type 从META-INF/spring.factories获取 具体的实现类字符串列表 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 实例化具体的实现类 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); // 排序 AnnotationAwareOrderComparator.sort(instances); return instances;Die Implementierungsklassenzeichenfolge, die ApplicationContextInitializer.class in der META-INF/spring.factories-Datei entspricht, lautet:
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializerIn META-INF/ spring.factories Die Implementierungsklassenzeichenfolge, die ApplicationListener.class in der Datei entspricht, lautet
org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener2. Der Code der Ausführungsmethode lautet wie folgt:
StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); // 设置了一个名为 java.awt.headless 的系统属性 // 其实是想设计应用程序,即使没有检测到显示器,也允许其启动 // 对于服务器来说,是不需要显示器的 ,所以要这样设置 configureHeadlessProperty(); // 获取 SpringApplicationRunListener 加载的是 EventPublishingRunListener // 获取启动时的监听器 SpringApplicationRunListeners listeners = getRunListeners(args); // 触发启动事件 listeners.starting(); try { // 构造一个应用程序的参数持有类 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 创建并配置环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 配置需要忽略的BeanInfo信息 configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); // 创建上下文对象 context = createApplicationContext(); // 加载配置的启动异常处理器 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 刷新前操作 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新应用上下文 完成 Spring 容器的初始化 refreshContext(context); // 刷新后操作 afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // 启动完成事件 listeners.started(context); // 执行 ApplicationRunner 和 CommandLineRunner 实现类 callRunners(context, applicationArguments); } catch (Throwable ex) { // 事件广播启动出错了 handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { // 运行事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context;Die Hauptlogik in der Ausführungsmethode:
# 🎜🎜#1. Rufen Sie die SpringApplicationRunListener-Implementierungsklasse (Herausgeber von Listening-Ereignissen) aus der Datei spring.factories ab und führen Sie verwandte Ereignisse im Kontextlebenszyklus aus, z. B. das Auslösen von Startereignissen und den Abschluss des Startvorgangs Veranstaltungen usw.
2. Erstellen Sie ein Webanwendungskontextobjekt und einen bestimmten Webdiensttyp basierend auf webApplicationType.
3. Kapseln Sie vor dem Aktualisieren die Hauptressourcen der Konfigurationsklasse in BeanDefinitionHolder und laden Sie sie in die Kontextregistrierung.
4. Aktualisieren Sie den Anwendungskontext, um die Initialisierung des Spring-Containers abzuschließen.
5. Ausführungsklassen, die die Schnittstellen ApplicationRunner und CommandLineRunner implementieren.
2. Analyse des automatischen Assembly-Prinzips von SpringBoot
1. Vorkenntnisse der automatischen Assembly @Import
@SpringBootApplication-Annotation, die hauptsächlich @ verwendet Annotation importieren, @Import-Quellcode lautet wie folgt:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { /** * {@link Configuration @Configuration}, {@link ImportSelector}, * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import. */ Class<?>[] value(); }
try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } }
1. Implementieren Sie das Schnittstellenszenario ImportSelector.class. Rufen Sie direkt die Methode selectImports des Instanzselektors auf, um die vollständige Klassennamenliste des zu instanziierenden Bean-Objekts zurückzugeben, und erstellen Sie das Instanzobjekt Rufen Sie dann rekursiv die aktuelle Methode „processImports“ auf, basierend auf der Zeichenfolgenliste mit den vollständigen Klassennamen, und fügen Sie sie schließlich der Sammlung „configurationClasses“ hinzu. Die Objekte in der Sammlung „configurationClasses“ werden im Registrierungsobjekt vom Typ BeanDefinitionRegistry registriert. In diesem Fall wird die Schnittstelle ImportSelector implementiert und die Schnittstelle DeferredImportSelector erweitert. Diese Schnittstelle wird verwendet, um die verzögerte Injektionsfunktion von BeanDefinition zu implementieren. Die DeferredImportSelector-Schnittstelle erweitert die ImportSelector-Schnittstelle und verfügt über eine interne Schnittstellengruppe. Wenn eine mit @Import annotierte Wertklasse die DeferredImportSelector-Schnittstelle und auch die interne Klassenschnittstelle der Schnittstelle implementiert, muss diese Implementierungsklasse anscheinend zurückgestellt werden. Wenn eine verzögerte Verarbeitung erforderlich ist, wird der ImportSelector-Instanzselektor in ein DeferredImportSelectorHolder-Objekt zusammengestellt und der deferredImportSelectors-Sammlung hinzugefügt. Der Speicherort des Quellcodes der Verarbeitungslogik: org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorHandler#handle; Es folgt
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) { DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector); if (this.deferredImportSelectors == null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); handler.register(holder); handler.processGroupImports(); } else { this.deferredImportSelectors.add(holder); } }
Die Implementierungslogik der DeferredImportSelector-Schnittstelle wird in der org.springframework.annotation.ConfigurationClassParser#parse-Methode aufgerufen. Der spezifische Code befindet sich in this.deferredImportSelectorHandler.process Der Schlüsselcode lautet wie folgt:
public void process() { List<DeferredImportSelectorHolder> 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<>(); } }
在processGroupImports()方法中,先通过grouping.getImports()拿到需要自动装配的Group.Entry(封装了全类名)对象集合,然后通过processImports()方法根据Entry类名字符串进行创建SourceClass类(该类可以通过asConfigClass()方法转成ConfigurationClass对象),最终添加到configurationClasses集合中。代码如下,
public void processGroupImports() { for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { Predicate<String> exclusionFilter = grouping.getCandidateFilter(); grouping.getImports().forEach(entry -> { ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata()); try { processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter), Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)), exclusionFilter, false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", ex); } }); } }
grouping.getImports()方法中主要执行具体的实现类的process方法和selectImports()方法(如果是AutoConfigurationImportSelector类,则调用org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process和org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports,两个方法的具体类容请看2.2.2章节的说明),selectImports返回需要自动装配的Group.Entry对象集合,Entry对象中保存了全类名。代码如下:
public Iterable<Group.Entry> getImports() { for (DeferredImportSelectorHolder deferredImport : this.deferredImports) { this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector()); } return this.group.selectImports(); }
ImportSelector接口代码代码如下:
public interface ImportSelector { String[] selectImports(AnnotationMetadata importingClassMetadata); @Nullable default Predicate<String> getExclusionFilter() { return null; } }
DeferredImportSelector接口的代码如下:
public interface DeferredImportSelector extends ImportSelector { @Nullable default Class<? extends Group> getImportGroup() { return null; } interface Group { void process(AnnotationMetadata metadata, DeferredImportSelector selector); Iterable<Entry> selectImports(); class Entry { // 省略 } } }
2.实现了 ImportBeanDefinitionRegistrar.class接口的场景;会先创建ImportBeanDefinitionRegistrar 实例类 registrar,再把 registrar 添加到 configClass 的 importBeanDefinitionRegistrars中,接口的registerBeanDefinitions方法的调用是在 org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions方法里的this.reader.loadBeanDefinitions(configClasses)代码中。具体执行语句loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());关键代码如下,
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) { registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator)); }
ImportBeanDefinitionRegistrar接口代码如下:
public interface ImportBeanDefinitionRegistrar { default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { registerBeanDefinitions(importingClassMetadata, registry); } default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } }
3.没有实现以上两接口的普通类,会直接调用org.springframework.context.annotation.ConfigurationClassParser#processImports里面的processConfigurationClass方法,把当前configClass添加至 configurationClasses 集合中。configurationClasses集合中的对象最终会被注册到BeanDefinitionRegistry类型的 registry 对象中。
@SpringApplication注解主要包括了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。代码如下,
@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) })
配置注解,包含了@Configuration注解,表明是配置类。
自动装配注解,主要逻辑是:根据 EnableAutoConfiguration 类型从META-INF/spring.factories 文件加载需要自动装配的类,并注入到Spring容器中。它包括了@AutoConfigurationPackage注解和一个@Import(AutoConfigurationImportSelector.class)注解。代码如下,
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class)
注册名为 org.springframework.boot.autoconfigure.AutoConfigurationPackages ,BeanClass为BasePackages.class 的GenericBeanDefinition 到 BeanDefinitionRegistry 中,通过@Import 注解实现注入功能,代码如下,
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }
AutoConfigurationPackages.Registrar.class实现了ImportBeanDefinitionRegistrar接口 ,所以在Spring容器初始化的过程中会调用它的registerBeanDefinitions方法把PackageImport类注入到Spring容器中去。代码如下,
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImport(metadata).getPackageName()); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImport(metadata)); } }
自动装配关键逻辑,先从META-INF/spring.factories 文件加载类型值为 EnableAutoConfiguration的字符串集合,再通过过滤,生成需要自动装配的类,最后注入到Spring容器中。AutoConfigurationImportSelector实现了DeferredImportSelector接口并且内部也实现了DeferredImportSelector.Group接口,所以在Spring容器初始化的过程中会调用
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process方法和#selectImports方法,
process()用来生成需要自动装配的类型,方法的代码如下,
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); // 1. getAutoConfigurationMetadata() // 从META-INF/spring-autoconfigure-metadata.properties文件中获取自动装配的元数据, // 里面保存了加载类是否自动装配的条件 , // org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration.ConditionalOnBean // =javax.jms.ConnectionFactory // 2. getAutoConfigurationEntry() // 从 META-INF/spring.factories 文件中获取key为 EnableAutoConfiguration 的配置类字符串类表 并封装成 自动装配类对象 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); // 循环遍历 自动装配类对象 的自动装配类字符串 ,添加到 this.entries for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); }
getAutoConfigurationMetadata() 方法主要逻辑是:从META-INF/spring-autoconfigure-metadata.properties文件中获取自动装配的元数据,里面保存了自动加载类是否符合自动装配的前置条件,比较熟悉的有ConditionalOnClass和ConditionalOnBean,文件相关内容如下:
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration= org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.Flux,org.springframework.data.cassandra.core.ReactiveCassandraTemplate org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration.ConditionalOnClass=org.apache.solr.client.solrj.SolrClient,org.springframework.data.solr.repository.SolrRepository org.springframework.boot.autoconfigure.security.oauth3.client.servlet.OAuth3ClientAutoConfiguration.ConditionalOnWebApplication=SERVLET org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration= org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration.AutoConfigureBefore=org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration org.springframework.boot.autoconfigure.jms.artemis.ArtemisXAConnectionFactoryConfiguration= org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration.ConditionalOnWebApplication=REACTIVE org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration.ConditionalOnWebApplication=REACTIVE org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration= org.springframework.boot.autoconfigure.security.oauth3.resource.servlet.OAuth3ResourceServerAutoConfiguration.ConditionalOnWebApplication=SERVLET org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration.ConditionalOnWebApplication=SERVLET //省略
getAutoConfigurationEntry()方法 主要逻辑是:从spring.factories 文件中获取key为 EnableAutoConfiguration 的配置类字符串列表并封装成自动装配类AutoConfigurationEntry对象,代码如下,
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // 获取注解元数据的属性 AnnotationAttributes attributes = getAttributes(annotationMetadata); // 从spring.factories 文件中获取key为 EnableAutoConfiguration 的配置类字符串列表 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 去掉重复的 自动装配类字符串 configurations = removeDuplicates(configurations); // 根据注解元数据获取 需要排除的类名 Set<String> exclusions = getExclusions(annotationMetadata, attributes); // 检查排除的类名 checkExcludedClasses(configurations, exclusions); // 根据排除的类名进行排除 configurations.removeAll(exclusions); // 从spring.factories 文件中获取key为 AutoConfigurationImportFilter 的配置对象进行过滤 // 过滤规则从 getAutoConfigurationMetadata() 返回类的数据中获取 configurations = filter(configurations, autoConfigurationMetadata); // 执行导入配置类的监听事件 fireAutoConfigurationImportEvents(configurations, exclusions); // 返回 AutoConfigurationEntry 对象 return new AutoConfigurationEntry(configurations, exclusions); }
getCandidateConfigurations()方法从spring.factories 文件中获取类型为 EnableAutoConfiguration 的配置类字符串列表,代码如下,
// getSpringFactoriesLoaderFactoryClass()方法返回 EnableAutoConfiguration List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations;
在META-INF/spring.factories文件中EnableAutoConfiguration .class 对应的实现类字符串为
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ // 省略
2.selectImports()方法返回排序后的 Entry(需要自动装配的包装实体类) 对象集合,代码如下,
public Iterable<Entry> selectImports() { if (this.autoConfigurationEntries.isEmpty()) { return Collections.emptyList(); } Set<String> allExclusions = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet()); Set<String> processedConfigurations = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream) .collect(Collectors.toCollection(LinkedHashSet::new)); processedConfigurations.removeAll(allExclusions); // 返回排序后的 Entry 集合 return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream() .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)) .collect(Collectors.toList()); }
注意:@EnableAutoConfiguration 注解的分析过程需要结合@Import注解的过程来看。
Component-Scan-Annotation wird verwendet, um den automatischen Scan-Paketpfad zu konfigurieren. Wenn kein Konfigurationspfad vorhanden ist, werden alle Pakete und Klassen unter dem Namensraum der Hauptkonfigurationsklasse gescannt.
Das obige ist der detaillierte Inhalt vonWas ist der SpringBoot-Startcode und der Quellcode für die automatische Assemblierung?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!