【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
在这里插入图片描述
在这里插入图片描述

    @Configuration
    
    // 是否自动配置的条件
    @ConditionalOnWebApplication(type = Type.SERVLET)
    // 判断是否有下面三个的配置的
    @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
    @ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
    
    
    @AutoConfigureOrder(-2147483638)
    @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
    public class WebMvcAutoConfiguration {

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 {
            // 准备命令行参数,就是传入的args
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 准备环境,完成后,回调listener的environmentPrepared方法。
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            // 打印SpringBoot的logo
            Banner 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);
        }
    }
发布了34 篇原创文章 · 获赞 14 · 访问量 1568

猜你喜欢

转载自blog.csdn.net/Wan_Yuan/article/details/104873476
今日推荐