• springboot创建,自动装配原理分析,run方法启动


    使用IDEA快速创建一个springboot项目

    创建Spring Initializr,然后一直下一步下一步直至完成

    选择web,表示创建web项目

    运行原理分析

    我们先来看看pom.xml文件

    核心依赖的父项目如下:

    <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>2.2.1.RELEASE</version>
          <relativePath/> <!-- lookup parent from repository -->
    </parent>

    进入spring-boot-starter-parent,可以看到管理SpringBoot应用里面所有依赖版本的地方和配置加载的地方。

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>//管理SpringBoot应用里面所有依赖版本的地方
        <version>2.2.1.RELEASE</version>
        <relativePath>../../spring-boot-dependencies</relativePath>
    </parent>

    在进入spring-boot-dependencies,就可以看到所依赖的所有版本了,由于太过,这里只截取部分。

    所以,以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了。

    springboot自动配置原理分析

    主程序

    //@SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
    @SpringBootApplication
    public class Springboot01Application {
        public static void main(String[] args) {
            SpringApplication.run(Springboot01Application.class, args);
        }
    }
    @SpringBootApplication意义:SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
    进入@SpringBootApplication会发现有三个重要的注解
    • @SpringBootConfiguration:SpringBoot的配置类 ;标注在某个类上 , 表示这是一个SpringBoot的配置类;
    • @EnableAutoConfiguration:开启自动配置功能
    • @ComponentScan:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中 ;

    下面我们依次看一下这三个注解

    @SpringBootConfiguration

    进入@SpringBootConfiguration后,会看到@Configuration这个注解。

    @Configuration:配置类上来标注这个注解,说明这是一个配置类 ,配置类,即:配置文件

    在进入@Configuration后,会看到@Component注解,这个注解大家都很熟悉了吧,说明容器中的一个组件,也就是说启动类本身也是Spring中的一个组件而已,负责启动应用而已

    返回来我们再看@ComponentScan

    @ComponentScan

    @ComponentScan在Spring中非常重要,它对应XML配置中的元素。功能就是自动扫描并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中 ;

    接下来在看最重要的一个@EnableAutoConfiguration

    @EnableAutoConfiguration

    @EnableAutoConfiguration的作用是:开启自动配置功能,无须我们在自己配置,自动就告诉SpringBoot开启自动配置功能,这样自动配置才能生效;

    进入@EnableAutoConfiguration后会发下有两个注解,@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)

    @AutoConfigurationPackage //自动配置包
    @Import(AutoConfigurationImportSelector.class) //导入哪些组件的选择器
    public @interface EnableAutoConfiguration {
          ... ...
    }

    进入@AutoConfigurationPackage(自动配置包),有一个@Import(AutoConfigurationPackages.Registrar.class)。

    @Import注解大家都知道,是Spring底层注解, 给容器中导入一个组件。

    Registrar.class 将主配置类【即@SpringBootApplication标注的类】的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;

    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
    
    }

    接下返回@EnableAutoConfiguration看下@Import(AutoConfigurationImportSelector.class)(给容器导入组件)。

    AutoConfigurationImportSelector:自动配置导入选择器。

    我们来思考下,它会导入哪些组件的选择器呢?进入这个类,我们来看源码

    在类中找到这样一个方法

    // 获得候选的配置
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
       //这里的getSpringFactoriesLoaderFactoryClass()方法
        //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
            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;
    }

    getSpringFactoriesLoaderFactoryClass()

    这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
            String factoryTypeName = factoryType.getName();
         //这里它又调用了 loadSpringFactories 方法
            return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    我们继续点击查看 loadSpringFactories 方法

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
            MultiValueMap<String, String> result = cache.get(classLoader);
            if (result != null) {
                return result;
            }
            try {
            //去获取一个资源 "META-INF/spring.factories"
                Enumeration<URL> urls = (classLoader != null ?
                        classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                        ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                result = new LinkedMultiValueMap<>();
            //将读取到的资源遍历,封装成为一个Properties
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    for (Map.Entry<?, ?> entry : properties.entrySet()) {
                        String factoryTypeName = ((String) entry.getKey()).trim();
                        for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }
                cache.put(classLoader, result);
                return result;
            }
            catch (IOException ex) {
                throw new IllegalArgumentException("Unable to load factories from location [" +
                        FACTORIES_RESOURCE_LOCATION + "]", ex);
            }
    }

    我们进入FACTORIES_RESOURCE_LOCATION

    看到了这个路径:META-INF/spring.factories
    FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
    接下来我们就找一下这个配置文件
    找到spring-boot-autoconfigure-2.2.1.RELEASE.jar - META-INF - spring.factories文件

    这些都是自动配置根源

    进入我们熟悉的WebMvcAutoConfiguration,都是JavaConfig配置类,而且都注入了一些Bean

     总结

    springboot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但不一定生效,要判断条件是否成立,只要导入对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功。

    结论

    1、SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
    2、将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
    3、以前我们需要自己配置的东西 , 自动配置类都帮我们解决了
    4、整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
    5、它将所有需要导入的组件以全类名的方式返回 , 这些组件就会被添加到容器中 ;
    6、容器中存在非常多xxxAutoConfiguration的文件(@Bean), 就是给容器中导入这个场景需要的所有组件 ,并自动配置 ,@Configuration,javaConfig;
    7、有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

    流程图:https://www.processon.com/view/link/5de763fee4b00e6d9017b5e5

    run()方法

    @SpringBootApplication
    public class Springboot01Application {
        public static void main(String[] args) {
            //该方法返回一个ConfigurableApplicationContext对象
            //参数一:应用入口的类     参数类:命令行参数
            SpringApplication.run(Springboot01Application.class, args);
        }
    }    

    run()做了四件事:

    1. 推断应用的类型是普通的项目还是Web项目
    2. 查找并加载所有可用初始化器,设置到initializers属性中
    3. 找出所有的应用程序监听器,设置到listeners属性中
    4. 推断并设置main方法的定义类,找到运行的主类

  • 相关阅读:
    Java常用类之【日期相关类】
    Java常用类之【Math类、Random类、System类、Runtime类】
    Java常用类之【字符串相关类型】
    Java常用类之【八种基本数据类型】
    打印杨辉三角--for循环
    Eclipse设置文字大小
    Eclipse之JSON导包
    Java中设计模式之工厂模式-4
    PC 微信页面倒计时代码 safari不兼容date的问题
    在apache中设置访问目录后进入的默认页面为index.php
  • 原文地址:https://www.cnblogs.com/niudaben/p/11981690.html
Copyright © 2020-2023  润新知