當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
【Spring框架家族】SpringBoot自动配置原理源码跟进
生活随笔
收集整理的這篇文章主要介紹了
【Spring框架家族】SpringBoot自动配置原理源码跟进
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
繼承springboot父工程依賴pox.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.8.RELEASE</version></dependency>spring-boot-starter-parent繼承了spring-boot-dependencies
- 這個依賴中定義了常用依賴的版本,以及鎖定了其版本,所以我們在導入starter時,無需定義版本
- 若沒有在這里定義版本,則需要自己導入相應的版本信息,如mysql的jdbc驅動
starter【web】啟動器
<!-- 導入了web模塊正常運行所依賴的組件,DispatcherServlet,內置tomcat容器等等--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>spring-boot-starter-web:
<!-- 這是springboot的基礎依賴,基本所有的啟動器都依賴于spring-boot-starter。其依賴內容包括自動配置,日志,注解,spring核心,yaml等。 導入了相應的starter后,springboot就會自動配置其運行組件springboot官方定義的啟動器依賴都是以 spring-boot-starter 開頭的。【spring-boot-starter-xxx】如果官方沒有定義,其他技術需要集成springboot,則需要自己定義啟動器依賴,如 mybatis 【mybatis-spring-boot-starter】--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.1.8.RELEASE</version><scope>compile</scope></dependency>@SpringBootApplication注解
// 標記當前是一個啟動引導類,是springboot應用的入口。// 本身是一個組合注解。@SpringBootConfiguration // 點擊@EnableAutoConfiguration // 點擊// 包掃描器,不包含excludeFilters以下過濾注解@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM,classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {//...............}@SpringBootConfiguration
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Configuration //點擊public @interface SpringBootConfiguration {}@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Component // 表示該注解是一個配置類注解,并且自己是容器中的一個組件public @interface Configuration { @AliasFor( annotation = Component.class ) String value() default "";}@EnableAutoConfiguration
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage // 點擊@Import({AutoConfigurationImportSelector.class})public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};}@AutoConfigurationPackage
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited// 自定義化配置包掃描,指定要掃描的包@Import({Registrar.class}) // 點擊public @interface AutoConfigurationPackage {}static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {Registrar() {}public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());}public Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));}}private final String packageName;public String getPackageName() {// 包名:就是Spring容器需要去掃描能夠識別的注解。其實就是啟動引導類所在的包及其子包return this.packageName;}@AutoConfigurationImportSelector
public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {// 獲取自動化配置的元數據AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);// 通過配置的元數據和注解的元數據,得到一個自動化配置的entry鍵值對AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}} protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {// 獲取注解的屬性AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 通過注解元數據和屬性獲取真正意義上的集合List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = this.filter(configurations, autoConfigurationMetadata);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}} protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;}public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {String factoryClassName = factoryClass.getName();return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);if (result != null) {return result;} else {try {// 加載配置文件中的信息Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");LinkedMultiValueMap result = new LinkedMultiValueMap();while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);// 遍歷配置文件中的信息,轉換為Properties對象,放入到信息中Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator var6 = properties.entrySet().iterator();// 遍歷while(var6.hasNext()) {Entry<?, ?> entry = (Entry)var6.next();// 獲取工廠類名稱String factoryClassName = ((String)entry.getKey()).trim();String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());int var10 = var9.length;for(int var11 = 0; var11 < var10; ++var11) {String factoryName = var9[var11];result.add(factoryClassName, factoryName.trim());}}}// 添加緩存cache.put(classLoader, result);return result;} catch (IOException var13) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);}}}META-INF/spring.factories
SpringApplication.run(XXX.class, args)
// public static ConfigurableApplicationContext run()返回一個Spring容器對象public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return (new SpringApplication(primarySources)).run(args);}創建SpringApplication對象
public SpringApplication(Class... primarySources) {this((ResourceLoader)null, primarySources);} public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {this.sources = new LinkedHashSet();this.bannerMode = Mode.CONSOLE;this.logStartupInfo = true;this.addCommandLineProperties = true;this.addConversionService = true;this.headless = true;this.registerShutdownHook = true;this.additionalProfiles = new HashSet();this.isCustomEnvironment = false;this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));// 判斷當前是否是web環境this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 從類路徑下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;// 然后封裝成一個Map,轉成Set,遍歷Set,通過反射創建對象,// 賦值給SpringApplication的initializers屬性this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));// 從類路徑下找到META‐INF/spring.factories配置的所有ApplicationListener;// 然后封裝成一個Map,轉成Set,遍歷Set,通過反射創建對象,// 賦值給SpringApplication的listeners屬性this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));// 從多個配置類中找到有main方法的主配置類this.mainApplicationClass = this.deduceMainApplicationClass();}執行run方法
public ConfigurableApplicationContext run(String... args) {// 創建StopWatch對象,執行start方法,開始計時。StopWatch用來計算run方法的執行時間StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();this.configureHeadlessProperty();// 從類路徑下META‐INF/spring.factories中獲取SpringApplicationRunListeners,// 反射創建對象,并回調start方法;SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting();Collection exceptionReporters;try {// 準備命令行參數,就是傳入的argsApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 準備環境,完成后,回調listener的environmentPrepared方法。ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);this.configureIgnoreBeanInfo(environment);// 打印SpringBoot的logoBanner printedBanner = this.printBanner(environment);// 創建Spring容器,通過判斷,決定是web的Spring容器還是普通的Spring容器context = this.createApplicationContext();exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);// 準備上下文環境this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 刷新容器,加載所有的組件【如果是web環境,會啟動tomcat】this.refreshContext(context);this.afterRefresh(context, applicationArguments);// 停止計時,stopWatch.stop();if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}// 回調所有的SpringApplicationRunListener的started();listeners.started(context);// 從ioc容器中獲取所有的ApplicationRunner和CommandLineRunner進行回調// 【ApplicationRunner先回調,CommandLineRunner再回調】this.callRunners(context, applicationArguments);} catch (Throwable var10) {this.handleRunFailure(context, var10, exceptionReporters, listeners);throw new IllegalStateException(var10);}try {listeners.running(context);return context;} catch (Throwable var9) {this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);throw new IllegalStateException(var9);}}總結
以上是生活随笔為你收集整理的【Spring框架家族】SpringBoot自动配置原理源码跟进的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Spring框架家族】SpringBo
- 下一篇: 【Spring框架家族】Spring C