日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

原理解析_SpringBoot自动装配原理解析

發布時間:2025/3/13 javascript 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 原理解析_SpringBoot自动装配原理解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

自動裝配是Spring Boot的核心部分,也是Spring Boot功能的基礎,正是由于自動裝配,才將我們從Bean的繁復配置中解脫出來。那么Spring Boot中的自動裝配指的是什么?我們繼 續以Spring MVC為例,不使用Spring Boot 時,我們可能需要配置視圖解析器,文件解析器, 請求適配器等等各種 Bean, 如果在使用數據庫Redis,還需要配置數據庫Redis相關Bean。

一、從@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 { @AliasFor(annotation = EnableAutoConfiguration.class) Class>[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {};//根據包路徑掃描 @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {};//直接根據 class 類掃描 @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class>[] scanBasePackageClasses() default {}; }

初看@SpringBootApplication有很多的注解組成,其實歸納就是一個三體結構,重要的只有三個Annotation:

  • @Configuration(@SpringBootConfiguration實質就是一個@Configuration)

  • @EnableAutoConfiguration

  • @ComponentScan

  • 也就是說我們在開發的時候,加上上面的三個注解會等同于加上@SpringBootApplication 注解。

    @Configuration 注解 :

    這個注解實際上就是代表了一個配置類,相當于一個beans.xml文件 ;

    @ComponentScan 注解:

    @ComponentScan 的功能其實就是自動掃描并加載符合條件的組件或bean定義,最終將這些bean定義加載到容器中 ;

    @EnableAutoConfiguration ?注解:

    在spring中有關于@Enablexxx 的注解是開啟某一項功能的注解,比如@EnableScheduling 表示開啟spring 的定時任務。其原理是借助@Import的幫助,將所有符合自動配置條件的bean定義加載到Ioc容器;

    EnableAutoConfiguration代表開啟springboot的自動裝配。

    @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; //按類型排序不需要自動裝配的類 Class>[] exclude() default {}; //按名稱排除不需要自動裝配的類 String[] excludeName() default {}; }

    從上面源碼中我們可以知道,最關鍵的要屬@Import(EnableAutoConfigurationImportSelector.class),借助 EnableAutoConfigurationImportSelector 和 @EnableAutoConfiguration 可以幫助Spring Boot應用將所有符合條件的@Configuration配置都加載到當前SpringBoot 創建并使用的IoC容器。同時借助于 Spring 框架原有的一個工具類:SpringFactoriesLoader,@EnableAutoConfiguration 就可以實現智能的自動配置。

    從這里可以看出該類實現很多的xxxAware 和 DeferredImportSelector,所有的aware都優先于selectImports;

    方法執行,也就是說selectImports方法最后執行,那么在它執行的時候所有需要的資源都已經獲取到了

    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { ... public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { //1. 加載 META-INF/spring-autoconfigure-metadata.properties文件 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);//2. 獲取注解的屬性及其值(PS:注解指的是@EnableAutoConfiguration 注解) AnnotationAttributes attributes = this.getAttributes(annotationMetadata);//3. 在classpath下所有的 META-INF/spring.factories 文件中查找 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的值, 并將其封裝到一個 List 中返回 List configurations =this.getCandidateConfigurations(annotationMetadata, attributes); //4. 對上一步返回的 List 中的元素去重、排序 configurations = this.removeDuplicates(configurations);//5.依據第 2 步中獲取的屬性值排除一些特定的類 Set exclusions = this.getExclusions(annotationMetadata, attributes);//6. 對上一步中所得到的 List 進行過濾,過濾的依據是條件匹配。這里用到的過濾器是org.springframework.boot.autoconfigure.condition.OnClassCondition最終返回的是一個 ConditionOutcome[]數組。//(PS:很多類都是依賴于其它的類的,當有某個類時才會裝配,所以這次過濾的就是根據是否有某個class進而決定是否裝配的。這些類所依賴的類都寫在META-INF/spring-autoconfigure-metadata.properties 文件里) this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations,autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations,exclusions); return StringUtils.toStringArray(configurations); } }protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderF actoryClass(), 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; } ... }

    SpringFactoriesLoader中加載配置, SpringFactoriesLoader 屬于Spring框架私有的一種擴展方案,其主要功能就是從指定的配置文件META-INF/spring.factories加載配置, 即根據@EnableAutoConfiguration的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration作為查找的 Key, 獲取對應的一組@Configuration 類。

    public abstract class SpringFactoriesLoader { public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap result = cache.get(classLoader); if (result != null) return result; try { Enumeration 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()) { List factoryClassNames = Arrays.asList( StringUtils.commaDelimitedListToStringArray((String) entry.getValue())); result.addAll((String) entry.getKey(), factoryClassNames); } } cache.put(classLoader, result); return result; }catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }...

    總結:

    @EnableAutoConfiguration作用就是從classpath中搜尋所有的META-INF/spring.factories 配置文件,并將其中org.springframework.boot.autoconfigure.EnableutoConfiguration 對應的配置項通過反射(Java Refletion)實例化為對應的標注了@Configuration 的JavaConfig形式的IoC容器配置類,然后匯總為一個并加載到IoC容器。

    這些功能配置類要生效的話,會去classpath中找是否有該類的依賴類(也就是pom.xml 必須有對應功能的 jar 包才行)并且配置類里面注入了默認屬性值類,功能類可以引用并賦默認值。生成功能類的原則是自定義優先,沒有自定義時才會使用自動裝配類。

    所以功能類能生效需要的條件:

  • spring.factories 里面有這個類的配置類(一個配置類可以創建多個圍繞該功能的依賴類);
  • pom.xml里面需要有對應的JAR包。
  • 二、自動裝配案例說明 Redis為例

    1、從spring-boot-autoconfigure.jar/META-INF/spring.factories中獲取Redis的相關配置類全限定名(有 120 多個的配置類)RedisAutoConfiguration, 一般一個功能配置類圍繞該功能,負責管理創建多個相關的功能類,比如RedisAutoConfiguration負責:JedisConnectionFactory、RedisTemplate、StringRedisTemplate 這3個功能類的創建spring.factories中的Redis配置類 。

    2、RedisAutoConfiguration配置類生效的一個條件是在classpath路徑下有RedisOperations 類存在,因此Spring Boot 的自動裝配機制會去classpath下去查找對應的 class 文件。

    @Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { ...}

    3、如果 pom.xml 有對應的 jar 包,就能匹配到對應依賴 class

    org.springframework.boot spring-boot-starter-data-redis

    4、匹配成功, 這個功能配置類才會生效, 同時會注入默認的屬性配置類@EnableConfigurationProperties(RedisProperties.class)

    @ConfigurationProperties(prefix = "spring.redis") public class RedisProperties { private int database = 0; private String url; private String host = "localhost"; private String password; private int port = 6379; ...

    5、Redis功能配置里面會根據條件生成最終的JedisConnectionFactory、RedisTemplate,并提供了默認的配置形式`@ConditionalOnMissingBean(name =

    "redisTemplate") `

    @Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class)@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { @Bean //用戶沒定義就使用默認的 @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate redisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean(StringRedisTemplate.class) public StringRedisTemplate stringRedisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }

    6、最終創建好的默認裝配類,會通過功能配置類里面的 @Bean注解,注入到IOC當中

    7、用戶使用,當用戶在配置文件中自定義時候就會覆蓋默認的配置@ConditionalOnMissingBean(name = "redisTemplate")

    三、自動依賴過程總結

    1、通過各種注解實現了類與類之間的依賴關系,容器在啟動的時候Application.run,會調用EnableAutoConfigurationImportSelector.class 的selectImports 方法(其實是其父類的方法)

    這里需要注意,調用這個方法之前發生了什么和是在哪里調用這個方法需要進一步的探討。

    2、selectImports方法最終會調用SpringFactoriesLoader.loadFactoryNames方法來獲取一個全面的常用BeanConfiguration列表。

    3、loadFactoryNames 方法會讀取FACTORIES_RESOURCE_LOCATION(也就是 spring-boot-autoconfigure.jar 下面的 spring.factories),獲取到所有的Spring 相關的 Bean 的全限定名 ClassName,大概 120 多個 。

    4、 selectImports方法繼續調用 filter(configurations, ?autoConfigurationMetadata);這個時候會根據這些BeanConfiguration里面的條件,來一一篩選,最關鍵的是@ConditionalOnClass,這個條件注解會去 classpath 下查找,jar 包里面是否有這個條件依賴類,所以必須有了相應的 jar 包,才有這些依賴類,才會生成 IOC 環境需要的一些默認配置Bean。

    5、最后把符合條件的BeanConfiguration 注入默認的EnableConfigurationPropertie類里面的屬性值,并且注入到 IOC 環境當中。

    總結

    以上是生活随笔為你收集整理的原理解析_SpringBoot自动装配原理解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。