成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深度剖析Spring Boot自動裝配機(jī)制實(shí)現(xiàn)原理

不知名網(wǎng)友 / 2108人閱讀

摘要:所以,所謂的自動裝配,實(shí)際上就是如何自動將裝載到容器中來。實(shí)際上在版本中,模塊驅(qū)動注解的出現(xiàn),已經(jīng)有了一定的自動裝配的雛形,而真正能夠?qū)崿F(xiàn)這一機(jī)制,還是在版本中,條件注解的出現(xiàn)。,我們來看一下的自動裝配是怎么一回事。

Spring Boot自動裝配

在前面的分析中,Spring Framework一直在致力于解決一個(gè)問題,就是如何讓bean的管理變得更簡單,如何讓開發(fā)者盡可能的少關(guān)注一些基礎(chǔ)化的bean的配置,從而實(shí)現(xiàn)自動裝配。所以,所謂的自動裝配,實(shí)際上就是如何自動將bean裝載到Ioc容器中來。

實(shí)際上在spring 3.x版本中,Enable模塊驅(qū)動注解的出現(xiàn),已經(jīng)有了一定的自動裝配的雛形,而真正能夠?qū)崿F(xiàn)這一機(jī)制,還是在spirng 4.x版本中,conditional條件注解的出現(xiàn)。ok,我們來看一下spring boot的自動裝配是怎么一回事。

自動裝配的演示

      org.springframework.boot     spring-boot-starter-data-redis 
spring:    redis:      host: 127.0.0.1       port: 6379
 @Autowired    private RedisTemplateredisTemplate;

按照下面的順序添加starter,然后添加配置,使用RedisTemplate就可以使用了? 那大家想沒想過一個(gè)問題,為什么RedisTemplate可以被直接注入?它是什么時(shí)候加入到Ioc容器的呢? 這就是自動裝配。自動裝配可以使得classpath下依賴的包相關(guān)的bean,被自動裝載到Spring Ioc容器中,怎么做到的呢?

深入分析EnableAutoConfiguration

EnableAutoConfiguration的主要作用其實(shí)就是幫助springboot應(yīng)用把所有符合條件的@Configuration配置都加載到當(dāng)前SpringBoot創(chuàng)建并使用的IoC容器中。

再回到EnableAutoConfiguration這個(gè)注解中,我們發(fā)現(xiàn)它的import是這樣

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

但是從EnableAutoCOnfiguration上面的import注解來看,這里面并不是引入另外一個(gè)Configuration。而是一個(gè)ImportSelector。這個(gè)是什么東西呢?

AutoConfigurationImportSelector是什么?

Enable注解不僅僅可以像前面演示的案例一樣很簡單的實(shí)現(xiàn)多個(gè)Configuration的整合,還可以實(shí)現(xiàn)一些復(fù)雜的場景,比如可以根據(jù)上下文來激活不同類型的bean,@Import注解可以配置三種不同的class

  1. 第一種就是前面演示過的,基于普通bean或者帶有@Configuration的bean進(jìn)行諸如
  2. 實(shí)現(xiàn)ImportSelector接口進(jìn)行動態(tài)注入

實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口進(jìn)行動態(tài)注入

CacheService

public class CacheService {
}

LoggerService

public class LoggerService {
}

EnableDefineService

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented @Inherited  --允許被繼承@Import({GpDefineImportSelector.class})public @interface EnableDefineService {    String[] packages() default "";}

GpDefineImportSelector

public class GpDefineImportSelector implements ImportSelector {    @Override    public String[] selectImports(AnnotationMetadata annotationMetadata) {        //獲得指定注解的詳細(xì)信息。我們可以根據(jù)注解中配置的屬性來返回不同的class,        //從而可以達(dá)到動態(tài)開啟不同功能的目的    annotationMetadata.getAllAnnotationAttributes(EnableDefineService.class.getName(),true)            .forEach((k,v) -> {                log.info(annotationMetadata.getClassName());                log.info("k:{},v:{}",k,String.valueOf(v));            });        return new String[]{CacheService.class.getName()};    }}

EnableDemoTest

@SpringBootApplication@EnableDefineService(name = "gupao",value = "gupao")public class EnableDemoTest {    public static void main(String[] args) {        ConfigurableApplicationContext ca=SpringApplication.run(EnableDemoTest.class,args);        System.out.println(ca.getBean(CacheService.class));        System.out.println(ca.getBean(LoggerService.class));    }}

了解了selector的基本原理之后,后續(xù)再去分析AutoConfigurationImportSelector的原理就很簡單了,它本質(zhì)上也是對于bean的動態(tài)加載。

@EnableAutoConfiguration注解的實(shí)現(xiàn)原理

了解了ImportSelector和ImportBeanDefinitionRegistrar后,對于EnableAutoConfiguration的理解就容易一些了

它會通過import導(dǎo)入第三方提供的bean的配置類:AutoConfigurationImportSelector

@Import(AutoConfigurationImportSelector.class)

從名字來看,可以猜到它是基于ImportSelector來實(shí)現(xiàn)基于動態(tài)bean的加載功能。之前我們講過Springboot @Enable*注解的工作原理ImportSelector接口selectImports返回的數(shù)組(類的全類名)都會被納入到spring容器中。

那么可以猜想到這里的實(shí)現(xiàn)原理也一定是一樣的,定位到AutoConfigurationImportSelector這個(gè)類中的selectImports方法

selectImports

public String[] selectImports(AnnotationMetadata annotationMetadata) {   if (!isEnabled(annotationMetadata)) {      return NO_IMPORTS;   }// 從配置文件(spring-autoconfigure-metadata.properties)中加載 AutoConfigurationMetadata   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader         .loadMetadata(this.beanClassLoader);// 獲取所有候選配置類EnableAutoConfiguration   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(         autoConfigurationMetadata, annotationMetadata);   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}

getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(      AutoConfigurationMetadata autoConfigurationMetadata,      AnnotationMetadata annotationMetadata) {   if (!isEnabled(annotationMetadata)) {      return EMPTY_ENTRY;   }//獲取元注解中的屬性   AnnotationAttributes attributes = getAttributes(annotationMetadata);//使用SpringFactoriesLoader 加載classpath路徑下META-INF/spring.factories中,//key= org.springframework.boot.autoconfigure.EnableAutoConfiguration對應(yīng)的value   List configurations = getCandidateConfigurations(annotationMetadata,         attributes);//去重   configurations = removeDuplicates(configurations);//應(yīng)用exclusion屬性   Set exclusions = getExclusions(annotationMetadata, attributes);   checkExcludedClasses(configurations, exclusions);   configurations.removeAll(exclusions);//過濾,檢查候選配置類上的注解@ConditionalOnClass,如果要求的類不存在,則這個(gè)候選類會被過濾不被加載   configurations = filter(configurations, autoConfigurationMetadata);   //廣播事件fireAutoConfigurationImportEvents(configurations, exclusions);   return new AutoConfigurationEntry(configurations, exclusions);}

本質(zhì)上來說,其實(shí)EnableAutoConfiguration會幫助springboot應(yīng)用把所有符合@Configuration配置都加載到當(dāng)前SpringBoot創(chuàng)建的IoC容器,而這里面借助了Spring框架提供的一個(gè)工具類SpringFactoriesLoader的支持。以及用到了Spring提供的條件注解@Conditional,選擇性的針對需要加載的bean進(jìn)行條件過濾

SpringFactoriesLoader

為了給大家補(bǔ)一下基礎(chǔ),我在這里簡單分析一下SpringFactoriesLoader這個(gè)工具類的使用。它其實(shí)和java中的SPI機(jī)制的原理是一樣的,不過它比SPI更好的點(diǎn)在于不會一次性加載所有的類,而是根據(jù)key進(jìn)行加載。

首先,SpringFactoriesLoader的作用是從classpath/META-INF/spring.factories文件中,根據(jù)key來加載對應(yīng)的類到spring IoC容器中。接下來帶大家實(shí)踐一下

創(chuàng)建外部項(xiàng)目jar

  org.springframework  spring-context  4.3.13.RELEASE

創(chuàng)建bean以及config

public class GuPaoCore {    public String study(){        System.out.println("good good study, day day up");        return "GuPaoEdu.com";    }}@Configurationpublic class GuPaoConfig {    @Bean    public GuPaoCore guPaoCore(){        return new GuPaoCore();    }}

創(chuàng)建另外一個(gè)工程(spring-boot)

把前面的工程打包成jar,當(dāng)前項(xiàng)目依賴該jar包

    com.gupaoedu.practice    Gupao-Core    1.0-SNAPSHOT

通過下面代碼獲取依賴包中的屬性

運(yùn)行結(jié)果會報(bào)錯(cuò),原因是GuPaoCore并沒有被Spring的IoC容器所加載,也就是沒有被EnableAutoConfiguration導(dǎo)入

@SpringBootApplicationpublic class SpringBootStudyApplication {    public static void main(String[] args) throws IOException {        ConfigurableApplicationContext ac=SpringApplication.run(SpringBootStudyApplication.class, args);        GuPaoCore gpc=ac.getBean(GuPaoCore.class);        System.out.println(gpc.study());    }}

解決方案

在GuPao-Core項(xiàng)目resources下新建文件夾META-INF,在文件夾下面新建spring.factories文件,文件中配置,key為自定配置類EnableAutoConfiguration的全路徑,value是配置類的全路徑

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gupaoedu.practice.GuPaoConfig

重新打包,重新運(yùn)行SpringBootStudyApplication這個(gè)類。

可以發(fā)現(xiàn),我們編寫的那個(gè)類,就被加載進(jìn)來了。

@EnableAutoConfiguration注解的實(shí)現(xiàn)原理

了解了ImportSelector和ImportBeanDefinitionRegistrar后,對于EnableAutoConfiguration的理解就容易一些了

它會通過import導(dǎo)入第三方提供的bean的配置類:AutoConfigurationImportSelector

@Import(AutoConfigurationImportSelector.class)

從名字來看,可以猜到它是基于ImportSelector來實(shí)現(xiàn)基于動態(tài)bean的加載功能。之前我們講過Springboot @Enable*注解的工作原理ImportSelector接口selectImports返回的數(shù)組(類的全類名)都會被納入到spring容器中。

那么可以猜想到這里的實(shí)現(xiàn)原理也一定是一樣的,定位到AutoConfigurationImportSelector這個(gè)類中的selectImports方法

selectImports

public String[] selectImports(AnnotationMetadata annotationMetadata) {   if (!isEnabled(annotationMetadata)) {      return NO_IMPORTS;   }// 從配置文件(spring-autoconfigure-metadata.properties)中加載 AutoConfigurationMetadata    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader         .loadMetadata(this.beanClassLoader);// 獲取所有候選配置類EnableAutoConfiguration   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(         autoConfigurationMetadata, annotationMetadata);   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}

getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(      AutoConfigurationMetadata autoConfigurationMetadata,      AnnotationMetadata annotationMetadata) {   if (!isEnabled(annotationMetadata)) {      return EMPTY_ENTRY;   }//獲取元注解中的屬性   AnnotationAttributes attributes = getAttributes(annotationMetadata);//使用SpringFactoriesLoader 加載classpath路徑下META-INF/spring.factories中,//key= org.springframework.boot.autoconfigure.EnableAutoConfiguration對應(yīng)的value   List configurations = getCandidateConfigurations(annotationMetadata,         attributes);//去重   configurations = removeDuplicates(configurations);//應(yīng)用exclusion屬性   Set exclusions = getExclusions(annotationMetadata, attributes);   checkExcludedClasses(configurations, exclusions);   configurations.removeAll(exclusions);//過濾,檢查候選配置類上的注解@ConditionalOnClass,如果要求的類不存在,則這個(gè)候選類會被過濾不被加載   configurations = filter(configurations, autoConfigurationMetadata);   //廣播事件fireAutoConfigurationImportEvents(configurations, exclusions);   return new AutoConfigurationEntry(configurations, exclusions);}

本質(zhì)上來說,其實(shí)EnableAutoConfiguration會幫助springboot應(yīng)用把所有符合@Configuration配置都加載到當(dāng)前SpringBoot創(chuàng)建的IoC容器,而這里面借助了Spring框架提供的一個(gè)工具類SpringFactoriesLoader的支持。以及用到了Spring提供的條件注解@Conditional,選擇性的針對需要加載的bean進(jìn)行條件過濾

版權(quán)聲明:本博客所有文章除特別聲明外,均采用 CC BY-NC-SA 4.0 許可協(xié)議。轉(zhuǎn)載請注明來自 Mic帶你學(xué)架構(gòu)
如果本篇文章對您有幫助,還請幫忙點(diǎn)個(gè)關(guān)注和贊,您的堅(jiān)持是我不斷創(chuàng)作的動力。歡迎關(guān)注「跟著Mic學(xué)架構(gòu)」公眾號公眾號獲取更多技術(shù)干貨!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/125380.html

相關(guān)文章

  • spring boot - 收藏集 - 掘金

    摘要:引入了新的環(huán)境和概要信息,是一種更揭秘與實(shí)戰(zhàn)六消息隊(duì)列篇掘金本文,講解如何集成,實(shí)現(xiàn)消息隊(duì)列。博客地址揭秘與實(shí)戰(zhàn)二數(shù)據(jù)緩存篇掘金本文,講解如何集成,實(shí)現(xiàn)緩存。 Spring Boot 揭秘與實(shí)戰(zhàn)(九) 應(yīng)用監(jiān)控篇 - HTTP 健康監(jiān)控 - 掘金Health 信息是從 ApplicationContext 中所有的 HealthIndicator 的 Bean 中收集的, Spring...

    rollback 評論0 收藏0
  • 超實(shí)用百道Java面試題

    摘要:是的簡稱,運(yùn)行環(huán)境,為的運(yùn)行提供了所需的環(huán)境。分割字符串,返回分割后的字符串?dāng)?shù)組。當(dāng)計(jì)算的值相同時(shí),我們稱之為沖突,的做法是用鏈表和紅黑樹存儲相同的值的。迭代器取代了集合框架中的,迭代器允許調(diào)用者在迭代過程中移除元素。 Java基礎(chǔ)1.JDK和JRE有什么區(qū)別? JDK 是java development kit的簡稱,java開發(fā)工具包,提供java的開發(fā)環(huán)境和運(yùn)行環(huán)境。JRE 是j...

    MkkHou 評論0 收藏0
  • Java 最常見 200+ 面試題全解析:面試必備(附答案)

    摘要:的簡稱,運(yùn)行環(huán)境,為的運(yùn)行提供了所需環(huán)境。分割字符串,返回一個(gè)分割后的字符串?dāng)?shù)組。線程安全是線程安全的,而是非線程安全的。迭代器取代了集合框架中的,迭代器允許調(diào)用者在迭代過程中移除元素。 本文分為十九個(gè)模塊,分別是:?Java 基礎(chǔ)、容器、多線程、反射、對象拷貝、Java Web 、異常、網(wǎng)絡(luò)、設(shè)計(jì)模式、Spring/Spring MVC、Spring Boot/Spring Clou...

    hufeng 評論0 收藏0
  • SpringBoot究竟是如何跑起來的?

    摘要:你可以試著沿著調(diào)用棧代碼一層一層的深入進(jìn)去,如果你不打斷點(diǎn),你根本不知道接下來程序會往哪里流動。接下來再看看運(yùn)行時(shí)堆棧,看看一個(gè)請求的調(diào)用棧有多深。就是如此被自動裝配進(jìn)的。 摘要: 神奇的SpringBoot。 原文:SpringBoot 究竟是如何跑起來的? 作者:老錢 Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 不得不說 SpringBoot 太復(fù)雜了,我本來只想研究一下...

    DevWiki 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<