SpringBoot原理

2021-04-25  本文已影响0人  小鱼_a563

SpringBoot最大特点:自动装配

pom.xml

启动器

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

注解

@SpringBootApplication//springboot启动注解,启动类下面所有的资源被导入,下面有很多子注解
@SpringBootConfiguration//SpringBoot配置注解
@ComponentScan//包扫描注解,扫描同级及其下面的包注入到应用中
@EnableAutoConfiguration//启用自动配置注解---重要
@AutoConfigurationPackage//自动配置包
@Import({AutoConfigurationImportSelector.class})//导入AutoConfigurationImportSelector类(自动配置选择类)----重要

AutoConfigurationImportSelector

  public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            //获取自动配置实体类
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
 //获取自动配置实体类
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //通过配置文件获取所有的start启动器,返回一个集合(getCandidateConfigurations)
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }
//从字面意思就是获取获取候选配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        //通过类名加载自动注入
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        //如果为null,就返回提示,在META-INF / spring.factories中找不到自动配置类。 如果您使用的是自定义包装,请确保该文件正确无误。这就告诉我们 spring.factories非常重要:里面告诉了我们所有的可以自动配置的类。当然我们也可以从loadFactoryNames()方法中的loadSpringFactories()方法知道是从spring.factories匹配类名,然后加载出来的
        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;
    }

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();
            try {
                //获取资源目录下面META-INF/spring.factories所有的url
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");
                while(urls.hasMoreElements()) {//有没有更多的子节点
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();
                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;
                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                //放入到缓存中
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

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

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

SpringApplication.run

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

上一篇下一篇

猜你喜欢

热点阅读