【SpringBoot】-- 核心原理

springboot是服務於spring框架的框架,可以幫助使用Spring的開發者快速構建Spring框架,它基於了約定由於配置的理念,服務的範圍是簡化配置文件;

1.約定由於配置:

約定優於配置,是一種軟件設計範式,目的在於減少開發人員需要做決定的數量,使開發變得簡單,但不失靈活

體現:

  • maven的目錄結構
    • 默認以jar的方式打包
    • 默認會有resource文件夾
    • 默認提供application.properties/yml文件
  • main方法運行就會啓動web工程,啓動時創建一個內置的tomcat容器,將當前項目部署在此容器中
  • 可以通過Spring,profiles.active屬性來決定運行不同環境讀取的配置文件
  • maven裏面引用了spring-boot-starter-web
    • 會自動添加spring mvc工程所需要的所有東西

2. 重點需要了解的內容

對spring 已有的東西進行封裝然後創建出來的新東西:

  1. AutoConfiguration 自動裝配
  2. Starter
  3. Actuator
  4. SpringBoot CLI

3.啓動類上的複合註解: @SpringBootApplication

本質上覆合了@EnableAutoConfiguration,@ComponentScan,@Configuration

  1. EnableAutoC onfiguration
    EnableAutoConfiguration 的 主要作用其實就是幫助springboot 應用把所有符合條件的@Configuration 配置都自動加載到當前 SpringBoot 創建並使用的 IOC 容器中
  2. ComponentScan
    掃描@Component/@Reponsitory/@Service/@Controller 攜帶了上面註解的類都會被掃描到IOC容器內託管
  3. Configuration
    任何一個標註了@Configuration 的 Java 類定義都是一個JavaConfig 配置類。而在這個配置類中,任何標註了@Bean 的方法,它的返回值都會作爲 Bean 定義註冊到Spring 的 IOC 容器,方法名默認成爲這個 bean 的 id;

4. Spring Boot 自動配置原理是什麼?

  1. 在複合註解SpringBootapplication中,包含EnableAutoConfiguration啓動spring應用程序上下文的自動配置,EnableAutoConfiguration內會導入一個AutoConfigurationImportSelector類詳細流程是這樣:
    (1)SpringApplication.run(AppConfig.class,args);執行流程,中有refreshContext(context);
    (2)refreshContext(context);內部會解析我們的配置類上的標籤.實現自動裝配功能的註解@EnableAutoConfiguration
    (3)會解析@EnableAutoConfiguration這個註解裏面的@Import引入的配置類.AutoConfigurationImportSelector
  2. 這個類會去讀取spring.factories下key爲EnableAutoConfiguration對應的全限定名的值;
  3. spring.factories裏配置的所有key-value,是要告訴springBoot這個stareter所需要加載的XXXAutoConfiguraion類,也就是我們想要自動注入的bean;

image.png
下的getCandidateConfigurations()

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        // 核心代碼 
        // 調用了方法:spring.core中的loadFactoryNames()
        // 參數1--this.getSpringFactoriesLoaderFactoryClass()
        // 參數2--this.getBeanClassLoader() 
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
    }
  • 參數1–this.getSpringFactoriesLoaderFactoryClass()
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }
  • 參數2–this.getBeanClassLoader()
    protected ClassLoader getBeanClassLoader() {
        return this.beanClassLoader;
    }
  • org.springframework.core.io.support.SpringFactoriesLoader類下的loadFactoryNames()
    
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                // 核心代碼看這裏
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                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 factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

5. SPI擴展點機制的實現和運用

Spring的SPI是什麼?
SPI的全名爲Service Provider Interface,爲某個接口尋找服務實現的機制,也叫擴展點機制,主要是爲了提升擴展性而存在;
當服務的提供者,提供了服務接口的一種實現之後,在jar包的META-INF/services/目錄裏同時創建一個以服務接口命名的文件。該文件裏就是實現該服務接口的具體實現類。而當外部程序裝配這個模塊的時候,就能通過該jar包META-INF/services/裏的配置文件找到具體的實現類名,並裝載實例化,完成模塊的注入。通過這個約定,就不需要把服務放在代碼中了,通過模塊被裝配的時候就可以發現服務類了
場景:
當SpringBoot裏面提供了默認實現不滿足我們的要求時候,我們可以對其進行擴展添加自己的實現
過程:
在resource/META-INFO下添加spring.fatories文件,配置相應的key,value
key:類的全路徑(固定的 )
value對應着所有的實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章