美文网首页
SpringBoot 启动原理

SpringBoot 启动原理

作者: 写代码的杰西 | 来源:发表于2020-08-11 21:58 被阅读0次

    参考原文

    SpringBoot干了什么?

    没有SpringBoot的时候,使用Spring开发应用程序,需要自己去手动像IoC容器里注册Bean。无论是xml还是JavaConfig。比如说集成MyBatis,需要xml或者JavaConfig去注入MyBatis的工厂类到Spring容器。集成很多第三方程序的时候就需要很多配置。这些配置对于新建一个项目来说,很多都是重复且相同的,比如MyBatis工厂类的包位置,相同版本的谁来新建都是写的一样的东西。SpringBoot就采用约定大于配置的思想,把集成到spring的组件,拆分成starter,来自动配置。

    核心原理

    首先看看springboot程序的注解@SpringBootApplication

    @SpringBootApplication
    public class StudyProApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(StudyProApplication.class, args);
        }
    
    }
    
    @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 @interface SpringBootApplication {
    ...
    }
    

    核心是这三个
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan

    @SpringBootConfiguration就是@Configuration,表明这是一个Spring JavaConfig类。
    @ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。不指定范围默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
    重点来看看@EnableAutoConfiguration

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
        /**
         * Exclude specific auto-configuration classes such that they will never be applied.
         * @return the classes to exclude
         */
        Class<?>[] exclude() default {};
    
        /**
         * Exclude specific auto-configuration class names such that they will never be
         * applied.
         * @return the class names to exclude
         * @since 1.3.0
         */
        String[] excludeName() default {};
    
    }
    

    @EnableAutoConfiguration是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器

    @AutoConfigurationPackage:自动配置包
    @Import: 导入自动配置的组件

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
    
        /**
         * Base packages that should be registered with {@link AutoConfigurationPackages}.
         * <p>
         * Use {@link #basePackageClasses} for a type-safe alternative to String-based package
         * names.
         * @return the back package names
         * @since 2.3.0
         */
        String[] basePackages() default {};
    
        /**
         * Type-safe alternative to {@link #basePackages} for specifying the packages to be
         * registered with {@link AutoConfigurationPackages}.
         * <p>
         * Consider creating a special no-op marker class or interface in each package that
         * serves no purpose other than being referenced by this attribute.
         * @return the base package classes
         * @since 2.3.0
         */
        Class<?>[] basePackageClasses() default {};
    
    }
    
    
    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    
            @Override
            public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
                register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
            }
    
            @Override
            public Set<Object> determineImports(AnnotationMetadata metadata) {
                return Collections.singleton(new PackageImports(metadata));
            }
    
        }
    

    new PackageImport(metadata).getPackageName(),它其实返回了当前主程序类的 同级以及子级 的包组件。

    @Import(AutoConfigurationImportSelector.class)注解:

    @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    
    
    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return EMPTY_ENTRY;
            }
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
            configurations = removeDuplicates(configurations);
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = getConfigurationClassFilter().filter(configurations);
            fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationEntry(configurations, exclusions);
        }
    

    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    它其实是去加载 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    寻找classpath下所有的spring.factories文件
    借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器

    相关文章

      网友评论

          本文标题:SpringBoot 启动原理

          本文链接:https://www.haomeiwen.com/subject/hvmydktx.html