zoukankan      html  css  js  c++  java
  • SpringBoot-02-原理初探之主启动类

    2. 原理初探

    2.1 pom.xml

    父依赖

    主要依赖一个父项目,主要管理项目的资源过滤和插件

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

    点进去,发现还有一个父依赖

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

    这里才是真正管理SpringBoot应用里所有依赖版本的地方,SpringBoot的版本控制中心;

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

    启动器 spring-boot-starter

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

    spring-boot-starter-web:帮我们导入web模块正常运行所依赖的组件。

    需要使用什么功能,就只需要找到对应的启动器即可!

    2.2 主启动类

    默认的主启动类

    //SpringBootApplication:标注这个类是一个SpringBoot的应用
    @SpringBootApplication
    public class Springboot01HelloApplication {
    
        public static void main(String[] args) {
            //将SpringBoot应用启动
            SpringApplication.run(Springboot01HelloApplication.class, args);
        }
    
    }
    

    注解:

    @SpringBootConfiguration:springboot的配置
    	@Configuration:spting配置类
    	@Component:说明这也是spring的组件
    	
    @EnableAutoConfiguration:自动配置
    	@AutoConfigurationPackage:自动配置包
    		@Import(AutoConfigurationPackages.Registrar.class):自动配置‘包注册’
    	@Import(AutoConfigurationImportSelector.class):自动配置导入
    
    //获取所有的配置
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    	
    

    获取候选的配置:

    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;
    }
    

    @SpringBootApplication

    作用:标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就运行在这个类的main方法上来启动SpringBoot应用。

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan (excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
          @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    	...
    }
    

    @ComponentScan

    它对应XML配置中的元素。

    作用:自动扫描并加载所有符合条件的组件或bean,将这个bean定义加载到IOC容器中。

    @SpringBootConfiguration

    作用:标注在类上,表示这是一个springboot的配置类

    继续点进去:

    @Configuration
    public @interface SpringBootConfiguration {
    	...
    }
    
    @Component
    public @interface Configuration {
    	...
    }
    

    这里出现的注解及解释:
    @Configuration :说明这是一个配置类,配置类就是对应Spring的xml配置文件

    @Component:说明启动类本身也是Spring中的一个组件,负责启动应用。

    @EnableAutoConfiguration

    作用:开启自动配置功能,即以前我们需要自己配置的东西,现在SpringBoot自动帮我们配置。

    点进该注解:

    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
        ...
    }
    

    这里出现的注解:

    @AutoConfigurationPackage:自动配置包

    Registrar.class的作用:将主启动类所在包及所有子包里的所有组件扫描到Spring容器中。

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

    @import:表示给容器导入一个组件

    @Import(AutoConfigurationImportSelector.class):给容器导入组件

    AutoConfigurationImportSelector:自动配置导入选择器,那么它到底导入了哪些组件的选择器呢?

    1. 这个类中有这样一个方法

      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;
      }
      
    2. 这个方法又调用了SpringFactoriesLoader类的静态方法:

      public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
         String factoryTypeName = factoryType.getName();
         return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
      }
      
    3. 继续点击查看loadSpringFactories方法

      private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
         MultiValueMap<String, String> result = cache.get(classLoader);
         if (result != null) {
            return result;
         }
      
         try {
            Enumeration<URL> urls = (classLoader != null ?
                  classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                  ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            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);
         }
      }
      
    4. 发现一个多次出现的文件:spring.factories,全局搜索它

    spring.factories

    ​ 我们根据源头打开spring.factories,看到很多自动配置的文件;这就是自动配置根源的所在!

    在这里插入图片描述

    WebMvcAutoConfiguration为例,打开:

    在这里插入图片描述

    ​ 可以看到一个个都是JavaConfig配置类,并且都注入了一些bean。

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

    结论

    1. SpringBoot在启动的时候从类路径META-INF/spring.factories中获取EnableAutoConfiguration指定的值;
    2. 将这些值作为自动配置类导入容器,自动配置类就生效,帮我们自动配置工作;
    3. 整个J2EE的整体解决方案和自动配置都在spring-autoconfigure的jar包中;
    4. 它会给容器中导入非常多的自动配置类(xxxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好;
    5. 有了自动配置类,免去了我们手动编写配置注入功能组件等工作。
  • 相关阅读:
    图像处理笔记(十)
    图像处理笔记(九):频率域滤波
    图像处理笔记(八)
    图像处理笔记(七)
    图像处理笔记(六):灰度变换与空间滤波
    分布式
    关于python代码是编译执行还是解释执行
    python中的元类metaclass
    Python的函数参数传递
    递推思想
  • 原文地址:https://www.cnblogs.com/CodeHuba/p/13697741.html
Copyright © 2011-2022 走看看