• springboot自动配置原理


    Springboot自动配置原理

    使用IDEA Spring Initializr快速创建一个Spring Boot项目

    @SpringBootApplication
    public class MyApplication {
        public static void main(String[] args) {SpringApplication.run(MyApplication .class, args);}
    }
    我们看到,MyApplication作为入口类,入口类中有一个main方法,这个方法其实就是一个标准的Java应用的入口方法,一般在main方法中使用SpringApplication.run()来启动整个应用。值得注意的是,这个入口类要使用@SpringBootApplication注解声明,它是SpringBoot的核心注解。
    @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 {
        //
    }

    @SpringBootApplication内部标注了三个注解:

    @SpringBootConfiguration进入源码中可以看见,@SpringBootConfiguration其实就是Spring中的@Configuration,用于标注配置类

    (SpringBootConfiguration是SpringBoot项目的配置注解,这也是一个组合注解,SpringBootConfiguration注解可以用java代码的形式实现spring中xml配置文件配置的效果,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。)

    @ComponentScan这个注解也是Spring中的,它用来将指定包下需要装配的组件注册到容器中(@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中)
    @EnableAutoConfiguration接下来才是今天的重头戏,Spring Boot自动配置的主角!
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
        //
    }
    可以看到,在@EnableAutoConfiguration注解内使用到了@import注解来完成导入配置的功能,而EnableAutoConfigurationImportSelector内部则是使用了SpringFactoriesLoader.loadFactoryNames方法进行扫描具有META-INF/spring.factories文件的jar包。
     
    @Import的作用就是导入一个类到IOC容器,我们先来看一下导入的这个类:自动配置导入选择器源码里有一个方法selectImports,选择导入

    AutoConfigurationImportSelector中方法selectImports的源码如下:
     @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        try {
              AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                        .loadMetadata(this.beanClassLoader);
              AnnotationAttributes attributes = getAttributes(annotationMetadata);
              //扫描具有META-INF/spring.factories文件的jar包
              List<String> configurations = getCandidateConfigurations(annotationMetadata,
                        attributes);
              //去重
              configurations = removeDuplicates(configurations);
              //排序
              configurations = sort(configurations, autoConfigurationMetadata);
               //删除需要排除的类
             Set<String> exclusions = getExclusions(annotationMetadata, attributes);
             checkExcludedClasses(configurations, exclusions);
             configurations.removeAll(exclusions);
             configurations = filter(configurations, autoConfigurationMetadata);
             fireAutoConfigurationImportEvents(configurations, exclusions);
             return configurations.toArray(new String[configurations.size()]);
        }
        catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }
    //加载spring.factories实现
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
        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;
    }
    任何一个springboot应用,都会引入spring-boot-autoconfigure,而spring.factories文件就在该包下面。spring.factories文件是Key=Value形式,多个Value时使用,隔开,该文件中定义了关于初始化,监听器等信息,而真正使自动配置生效的key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,如下所示:
    该方法会去获取所有自动配置类的名称。
     
    SpringFactoriesLoader类中给的loadFactoryNames的源码如下
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
            String factoryTypeName = factoryType.getName();
            return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
        }
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    可以看到该方法会扫描jar包路径下的META-INF/spring.factories 文件,把扫描到的这些文件内容包装成properties对象。再从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,并且把他们添加到容器中。
    1)SpringBoot启动会加载大量的自动配置类
    2)我们看我们需要的功能有没有SpringBoot默认写好的自动配置类;
    3)我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)
    4)给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这
    些属性的值;
     
    参考文章:
    https://www.jianshu.com/p/4a6094542f45


     
  • 相关阅读:
    centos 下查找软件安装在哪里的命令
    Ubuntu常用命令大全
    linux下vi命令大全
    查看linux系统版本命令
    Linux系统安装时分区的选择(推荐)
    Java subList的使用
    Java中unicode增补字符(辅助平面)相关用法简介
    Java编码方式再学
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 283. Move Zeroes
  • 原文地址:https://www.cnblogs.com/juquanyu-com/p/12974372.html
Copyright © 2020-2023  润新知