Springboot啟動(dòng)原理和自動(dòng)配置原理解析
放本地文件夾都快吃土了,準(zhǔn)備清理文件夾,關(guān)于Springboot的!
啟動(dòng)原理
@SpringBootApplication public class Start { public static void main(String[] args) { SpringApplication.run(Start.class, args); } }
SpringApplication
1、初始化
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.sources = new LinkedHashSet(); // this.bannerMode = Mode.CONSOLE;// 控制banner this.logStartupInfo = true;// 是否啟動(dòng)日志 this.addCommandLineProperties = true; // 讀取命令行配置 this.addConversionService = true; //添加轉(zhuǎn)換器 this.headless = true; // this.registerShutdownHook = true; // 注冊(cè)重啟 this.additionalProfiles = Collections.emptySet();// 讀取配置環(huán)境 this.isCustomEnvironment = false;// 是否是自定義環(huán)境 this.lazyInitialization = false; // 是否懶加載 this.applicationContextFactory = ApplicationContextFactory.DEFAULT; this.applicationStartup = ApplicationStartup.DEFAULT; // ApplicationStartup DEFAULT = new DefaultApplicationStartup(); this.resourceLoader = resourceLoader;// 資源加載器 Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // 主程序 this.webApplicationType = WebApplicationType.deduceFromClasspath();// SERVLET||REACTIVE; 是servlet還是reactive環(huán)境 // BootstrapRegistryInitializer this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); // ApplicationContextInitializer this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); // ApplicationListener this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
注冊(cè) BootstrapRegistryInitializer
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); // private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); // 1、從配置文件讀取名稱(chēng)加載 Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 2、獲取構(gòu)造器實(shí)例 List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); // 3、排序 AnnotationAwareOrderComparator.sort(instances); return instances; } // 1、加載配置 private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = (Map)cache.get(classLoader); if (result != null) { return result; } else { HashMap result = new HashMap(); try { //核心 從這里知道讀取配置文件位置 默認(rèn) Enumeration urls = classLoader.getResources("META-INF/spring.factories"); // ... 這里省略迭代器遍歷注冊(cè) result.replaceAll((factoryType, implementations) -> { return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); }); // 添加到緩存中,下次讀取。根據(jù)類(lèi)名讀取 cache.put(classLoader, result); return result; } catch (IOException var14) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14); } } } // 2、獲取構(gòu)造器實(shí)例 private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList(names.size()); Iterator var7 = names.iterator(); while(var7.hasNext()) { String name = (String)var7.next(); try { // 通過(guò)類(lèi)名反射機(jī)制調(diào)用,讀取Class<T> class Class<?> instanceClass = ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes); // 獲取構(gòu)造器實(shí)例 T instance = BeanUtils.instantiateClass(constructor, args); // 添加到構(gòu)造器中 instances.add(instance); } catch (Throwable var12) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12); } } // 返回 return instances; } // 排序 通過(guò)debug這里調(diào)用的是Integer類(lèi)型排序方法 List<Integer> list public static void sort(List<?> list) { if (list.size() > 1) { list.sort(INSTANCE); } }
配置文件
spring-boot:2.7.1.META-INF\spring.factorie
org.springframework.context.ApplicationContextInitializer=\ 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.ServerPortInfoApplicationContextInitializer
?
像 BootstrapRegistryInitializer
另外幾個(gè)配置是從其他配置文件中讀取的
例如
?
注冊(cè) ApplicationContextInitializer 、ApplicationListener
同 BootstrapRegistryInitializer
加載原理
2、調(diào)用run方法
核心
public ConfigurableApplicationContext run(String... args) { long startTime = System.nanoTime(); DefaultBootstrapContext bootstrapContext = this.createBootstrapContext(); ConfigurableApplicationContext context = null; this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); this.configureIgnoreBeanInfo(environment); Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 加載所有注解使用的掃描的組件 this.refreshContext(context); // 刷新 this.afterRefresh(context, applicationArguments); Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup); } listeners.started(context, timeTakenToStartup); this.callRunners(context, applicationArguments); } catch (Throwable var12) { this.handleRunFailure(context, var12, listeners); throw new IllegalStateException(var12); } try { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); return context; } catch (Throwable var11) { this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null); throw new IllegalStateException(var11); } }
所有組件經(jīng)過(guò)org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader
方法加載注冊(cè)組件
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) { AnnotationMetadata metadata = configClass.getMetadata(); AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata); ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef); configBeanDef.setScope(scopeMetadata.getScopeName()); String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry); AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata); BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // 在這里注冊(cè) this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition()); configClass.setBeanName(configBeanName); if (logger.isTraceEnabled()) { logger.trace("Registered bean definition for imported class '" + configBeanName + "'"); } }
org.springframework.beans.factory.support.DefaultListableBeanFactory
registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition())
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } // 注冊(cè) this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } }
自動(dòng)配置原理
該部分暫時(shí)找不到了,之前備份找不到了,先TODO下吧!喜歡的朋友參考下這篇文章:http://www.dbjr.com.cn/article/266763.htm
到此這篇關(guān)于Springboot啟動(dòng)原理和自動(dòng)配置原理解析的文章就介紹到這了,更多相關(guān)Springboot啟動(dòng)原理和自動(dòng)配置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Security OAuth 自定義授權(quán)方式實(shí)現(xiàn)手機(jī)驗(yàn)證碼
這篇文章主要介紹了Spring Security OAuth 自定義授權(quán)方式實(shí)現(xiàn)手機(jī)驗(yàn)證碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02基于Java實(shí)現(xiàn)遍歷文件目錄并去除中文文件名
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)遍歷文件目錄并去除中文文件名,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下2024-03-03Java web Hibernate如何與數(shù)據(jù)庫(kù)鏈接
這篇文章主要介紹了Java web Hibernate如何與數(shù)據(jù)庫(kù)鏈接,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06使用maven-assembly-plugin如何將system 依賴(lài)范圍的jar以class 方式
這篇文章主要介紹了使用maven-assembly-plugin如何將system 依賴(lài)范圍的jar以class 方式打包進(jìn) jar包中,本文給大家分享完美解決思路,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06java數(shù)學(xué)工具類(lèi)Math詳解(round方法)
這篇文章主要為大家詳細(xì)介紹了java數(shù)學(xué)工具類(lèi)Math,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08ZooKeeper入門(mén)教程三分布式鎖實(shí)現(xiàn)及完整運(yùn)行源碼
本文是ZooKeeper入門(mén)系列教程,分布式鎖有多種實(shí)現(xiàn)方式,比如通過(guò)數(shù)據(jù)庫(kù)、redis都可實(shí)現(xiàn)。作為分布式協(xié)同工具ZooKeeper,當(dāng)然也有著標(biāo)準(zhǔn)的實(shí)現(xiàn)方式。本文介紹在zookeeper中如何實(shí)現(xiàn)排他鎖2022-01-01Java運(yùn)行時(shí)數(shù)據(jù)區(qū)劃分原理解析
這篇文章主要介紹了Java運(yùn)行時(shí)數(shù)據(jù)區(qū)劃分原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04深入解析Java的設(shè)計(jì)模式編程中建造者模式的運(yùn)用
這篇文章主要介紹了深入解析Java的設(shè)計(jì)模式編程中建造者模式的運(yùn)用,同時(shí)文中也介紹了建造者模式與工廠模式的區(qū)別,需要的朋友可以參考下2016-02-02MyBatis 源碼分析 之SqlSession接口和Executor類(lèi)
mybatis框架在操作數(shù)據(jù)的時(shí)候,離不開(kāi)SqlSession接口實(shí)例類(lèi)的作用,下面通過(guò)本文給大家實(shí)例剖析MyBatis 源碼分析之SqlSession接口和Executor類(lèi),需要的朋友參考下吧2017-02-02