zoukankan      html  css  js  c++  java
  • SpringBoot-运行原理(四)

    1.自动配置

    (1).pom.xml

    在pom文件中

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

    在它的父工程中,有他的核心依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath>../../spring-boot-dependencies</relativePath>
    </parent>
    

    点进去,我们发现,springboot自动帮我们管理了依赖

    这只是其中的一小部分,我们在写或者引入有一些依赖的时候,不需要指定版本

    (2).启动器

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

    springboot-boot-starter:就是spring-boot的场景启动器

    这里的 spring-boot-starter-web 帮我们导入了web模块正常运行所依赖的组件;

    SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;

    (3).主程序(启动类)

    package com.bao;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class Springboot01HelloworldApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(Springboot01HelloworldApplication.class, args);
        }
    
    }
    

    @SpringBootApplication 来标注一个主程序类 , 说明这是一个Spring Boot应用

    run方法: 将Spring应用启动起来

    我们看一下@SpringBootApplication注解

    //四个标准注解
    @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 :SpringBoot的配置类 ,标注在某个类上,表示这是一个SpringBoot的配置类
    • @EnableAutoConfiguration : 启用自动配置,这个注解是让Spring Boot配置能够如此简化的关键性注解
    • @ComponentScan : 扫描当前主启动类同级的包

    点击@SpringBootConfiguration

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    public @interface SpringBootConfiguration {
    	@AliasFor(annotation = Configuration.class)
    	boolean proxyBeanMethods() default true;
    
    }
    

    @Configuration : 代表是一个spring配置类

    点击Configuration 发现有一个@Component,代表是一个spring组件

    点击@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 {};
    
    }
    

    主要是 :

    • @AutoConfigurationPackage
    • @Import(AutoConfigurationImportSelector.class)两个

    AutoConfigurationPackage(自动配置包)

    注解的作用是将 添加该注解的类所在的package 作为 自动配置package 进行管理。

    主要是Registrar.class

    package org.springframework.boot.autoconfigure;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.context.annotation.Import;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    //导入选择器
    @Import(AutoConfigurationPackages(自动配置注册包).Registrar.class)
    public @interface AutoConfigurationPackage {
    }
    

    @import :Spring底层注解@import , 给容器中导入一个组件 ,导入的组件由 {Registrar.class} 将主配置类 【即@SpringBootApplication标注的类】的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;

    @Import(AutoConfigurationImportSelector.class)

    • Import他的作用是给容器导入组件
    • AutoConfigurationImportSelector.class: (自动配置导入选择器)导入哪些组件的选择器

    它将所有需要导入的组件以全类名的方式返回 , 这些组件就会被添加到容器中 ;

    它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;

    有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

    点击AutoConfigurationImportSelector

    有这样的一个方法

    protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
                                                               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 = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationEntry(configurations, exclusions);
    }
    

    其中 getCandidateConfigurations:获取候选配置

    //获取所有配置
    List<String> configurations = 
        getCandidateConfigurations(annotationMetadata, attributes);
    

    点击getCandidateConfigurations

    里面的方法

    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;
    }
    
    //返回用来加载配置候选的类。标注了EnableAutoConfiguration注解的类(主启动类)
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }
    

    而在@SpringBootApplication注解中标注了@EnableAutoConfiguration

    所以就是启动类下的所有资源被导入

    在这里我们发现了META-INF/spring.factories文件.这个就是自动配置的核心文件

    我们去springboot的jar中寻找该文件

    List<String> configurations = SpringFactoriesLoader.loadFactoryNames
    (getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
    

    点击loadFactoryNames方法

    loadFactoryNames : 获取所有的加载配置

    返回的loadSpringFactories

    从这些资源中便利了所有的nextElement元素(也可以理解为自动配置)

    遍历完成后封装成Properties,供我们使用

    //所有资源加载到配置类中
    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    
    获取项目资源:classLoader.getResources(FACTORIES_RESOURCE_LOCATION) 
    获取系统资源:ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION))
    

    点击FACTORIES_RESOURCE_LOCATION,获取静态资源的位置

    META-INF/spring.factories获取配置文件

    需要导入对应的starter才能起作用

    例如

    由于@ConditionalOnClass的存在,会判断条件成立,才会加载配置这个类

    @ConditionalOnXXX如果这里面的条件都满足,才会生效

    (4).结论

    SpringBoot所有的自动配置都在启动类中扫描并加载,也就是spring.factories文件

    所有的自动配置类都在这个文件中,但是并不一定生效,要判断条件是否成立,只要导入对应的start,就会有对应的启动器,有了启动器,自动装配就会生效,然后就配置成功了

    1.springboot在启动的时候,会从类路径下META-INF/spring.factories文件中获取指定的值

    2.将这些自动配置的类导入容器,自动配置类就会生效,帮我们进行自动配置

    3.springboot帮我们做了我们以前需要的配置.

    4.整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;

    5.他会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器

    6.容器中也会存在非常多的XxxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景所需要的所有组件

    7.有了自动配置类,就不需要写配置文件

    我们找一个打开看看 : WebMvcAutoConfiguration

    所以,真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。

    2.Run

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

    SpringApplication.run分析

    分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;

    SpringApplication的实例化

    1.推断应用的类型是普通的项目还是Web项目

    2.查找并加载所有可用初始化器 , 设置到initializers属性中

    3.找出所有的应用程序监听器,设置到listeners属性中

    4.推断并设置main方法的定义类,找到运行的主类

    3.谈谈你对springboot的理解

    • 自动装配
    • run方法
    每个优秀的人,都有一段沉默的时光.那段时光,是付出很多努力,却得不到结果的日子,我们把他叫做扎根
  • 相关阅读:
    MATLAB计算机视觉与深度学习实战
    硬件创业:从产品创意到成熟企业的成功路线图
    Xcode5 创建模板和UIView 关联XIB
    iOS Development: Proper Use of initWithNibName:bundle: Affects UITableViewController
    自定义UIViewController与xib文件关系深入分析
    UIViewController XIB/NIB加载过程
    ios多视图开发中:xib与UIViewController的关联
    UIAlertView、UIActionSheet兼容iOS8
    Xcode6中怎么添加空工程模板
    [OC Foundation框架
  • 原文地址:https://www.cnblogs.com/sq-bmw/p/11924206.html
Copyright © 2011-2022 走看看