SpringBoot自動化配置的注解開關原理

我們以一個最簡單的例子來完成這個需求:定義一個注解EnableContentService,使用了這個注解的程序會自動注入ContentService這個bean。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(ContentConfiguration.class)
public @interface EnableContentService {}public interface ContentService {void doSomething();
}public class SimpleContentService implements ContentService {@Overridepublic void doSomething() {System.out.println("do some simple things");}
}

然后在應用程序的入口加上@EnableContentService注解。

這樣的話,ContentService就被注入進來了。 SpringBoot也就是用這個完成的。只不過它用了更加高級點的ImportSelector。

ImportSelector的使用

用了ImportSelector之后,我們可以在Annotation上添加一些屬性,然后根據屬性的不同加載不同的bean。

我們在@EnableContentService注解添加屬性policy,同時Import一個Selector。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(ContentImportSelector.class)
public @interface EnableContentService {String policy() default "simple";
}

這個ContentImportSelector根據EnableContentService注解里的policy加載不同的bean。

public class ContentImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {Class<?> annotationType = EnableContentService.class;AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(annotationType.getName(), false));String policy = attributes.getString("policy");if ("core".equals(policy)) {return new String[] { CoreContentConfiguration.class.getName() };} else {return new String[] { SimpleContentConfiguration.class.getName() };}}}

CoreContentService和CoreContentConfiguration如下:

public class CoreContentService implements ContentService {@Overridepublic void doSomething() {System.out.println("do some import things");}
}public class CoreContentConfiguration {@Beanpublic ContentService contentService() {return new CoreContentService();}
}

這樣的話,如果在@EnableContentService注解的policy中使用core的話,應用程序會自動加載CoreContentService,否則會加載SimpleContentService。

ImportSelector在SpringBoot中的使用

SpringBoot里的ImportSelector是通過SpringBoot提供的@EnableAutoConfiguration這個注解里完成的。

這個@EnableAutoConfiguration注解可以顯式地調用,否則它會在@SpringBootApplication注解中隱式地被調用。

@EnableAutoConfiguration注解中使用了EnableAutoConfigurationImportSelector作為ImportSelector。下面這段代碼就是EnableAutoConfigurationImportSelector中進行選擇的具體代碼:

@Override
public String[] selectImports(AnnotationMetadata metadata) {try {AnnotationAttributes attributes = getAttributes(metadata);List<String> configurations = getCandidateConfigurations(metadata,attributes);configurations = removeDuplicates(configurations); // 刪除重復的配置Set<String> exclusions = getExclusions(metadata, attributes); // 去掉需要exclude的配置configurations.removeAll(exclusions);configurations = sort(configurations); // 排序recordWithConditionEvaluationReport(configurations, exclusions);return configurations.toArray(new String[configurations.size()]);}catch (IOException ex) {throw new IllegalStateException(ex);}
}

其中getCandidateConfigurations方法將獲取配置類:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,AnnotationAttributes attributes) {return SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
}

SpringFactoriesLoader.loadFactoryNames方法會根據FACTORIES_RESOURCE_LOCATION這個靜態變量從所有的jar包中讀取META-INF/spring.factories文件信息:

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {String factoryClassName = factoryClass.getName();try {Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));List<String> result = new ArrayList<String>();while (urls.hasMoreElements()) {URL url = urls.nextElement();Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));String factoryClassNames = properties.getProperty(factoryClassName); // 只會過濾出key為factoryClassNames的值result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));}return result;}catch (IOException ex) {throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);}
}

getCandidateConfigurations方法中的getSpringFactoriesLoaderFactoryClass方法返回的是EnableAutoConfiguration.class,所以會過濾出key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的值。

下面這段配置代碼就是autoconfigure這個jar包里的spring.factories文件的一部分內容(有個key為org.springframework.boot.autoconfigure.EnableAutoConfiguration,所以會得到這些AutoConfiguration):

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\

當然了,這些AutoConfiguration不是所有都會加載的,會根據AutoConfiguration上的@ConditionalOnClass等條件判斷是否加載。

上面這個例子說的讀取properties文件的時候只會過濾出key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的值。

SpringBoot內部還有一些其他的key用于過濾得到需要加載的類:

  • org.springframework.test.context.TestExecutionListener

  • org.springframework.beans.BeanInfoFactory

  • org.springframework.context.ApplicationContextInitializer

  • org.springframework.context.ApplicationListener

  • org.springframework.boot.SpringApplicationRunListener

  • org.springframework.boot.env.EnvironmentPostProcessor

  • org.springframework.boot.env.PropertySourceLoader

轉載于:https://www.cnblogs.com/cmfwm/p/7993473.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/390601.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/390601.shtml
英文地址,請注明出處:http://en.pswp.cn/news/390601.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

hadoop將消亡_數據科學家:適應還是消亡!

hadoop將消亡Harvard Business Review marked the boom of Data Scientists in their famous 2012 article “Data Scientist: Sexiest Job”, followed by untenable demand in the past decade. [3]《哈佛商業評論 》在2012年著名的文章“數據科學家&#xff1a;最性感的工作…

劍指 Offer 15. 二進制中1的個數 and leetcode 1905. 統計子島嶼

題目 請實現一個函數&#xff0c;輸入一個整數&#xff08;以二進制串形式&#xff09;&#xff0c;輸出該數二進制表示中 1 的個數。例如&#xff0c;把 9 表示成二進制是 1001&#xff0c;有 2 位是 1。因此&#xff0c;如果輸入 9&#xff0c;則該函數輸出 2。 示例 1&…

[轉]kafka介紹

轉自 https://www.cnblogs.com/hei12138/p/7805475.html kafka介紹1.1. 主要功能 根據官網的介紹&#xff0c;ApacheKafka是一個分布式流媒體平臺&#xff0c;它主要有3種功能&#xff1a; 1&#xff1a;It lets you publish and subscribe to streams of records.發布和訂閱消…

如何開始android開發_如何開始進行Android開發

如何開始android開發Android開發簡介 (An intro to Android Development) Android apps can be a great, fun way to get into the world of programming. Officially programmers can use Java, Kotlin, or C to develop for Android. Though there may be API restrictions, …

httpd2.2的配置文件常見設置

目錄 1、啟動報錯&#xff1a;提示沒有名字fqdn2、顯示服務器版本信息3、修改監聽的IP和Port3、持久連接4 、MPM&#xff08; Multi-Processing Module &#xff09;多路處理模塊5 、DSO&#xff1a;Dynamic Shared Object6 、定義Main server &#xff08;主站點&#xff09; …

leetcode 149. 直線上最多的點數

題目 給你一個數組 points &#xff0c;其中 points[i] [xi, yi] 表示 X-Y 平面上的一個點。求最多有多少個點在同一條直線上。 示例 1&#xff1a; 輸入&#xff1a;points [[1,1],[2,2],[3,3]] 輸出&#xff1a;3 示例 2&#xff1a; 輸入&#xff1a;points [[1,1],[3,…

solidity開發以太坊代幣智能合約

智能合約開發是以太坊編程的核心之一&#xff0c;而代幣是區塊鏈應用的關鍵環節&#xff0c;下面我們來用solidity語言開發一個代幣合約的實例&#xff0c;希望對大家有幫助。 以太坊的應用被稱為去中心化應用&#xff08;DApp&#xff09;&#xff0c;DApp的開發主要包括兩大部…

2019大數據課程_根據數據,2019年最佳免費在線課程

2019大數據課程As we do each year, Class Central has tallied the best courses of the previous year, based on thousands of learner reviews. (Here are the rankings from 2015, 2016, 2017, and 2018.) 與我們每年一樣&#xff0c;根據數千名學習者的評論&#xff0c; …

2017-12-07 socket 讀取問題

1.用socke阻塞方式讀取服務端發送的數據時會出現讀取一直阻塞的情況&#xff0c;如果設置了超時時間會在超時時間后讀取到數據: 原因&#xff1a;在不確定服務器會不會發送 socket發送的數據不會返回null 或者-1 所以用常規的判斷方法是不行的。 解決辦法有兩個&#xff1a;1 …

靜態代理設計與動態代理設計

靜態代理設計模式 代理設計模式最本質的特質&#xff1a;一個真實業務主題只完成核心操作&#xff0c;而所有與之輔助的功能都由代理類來完成。 例如&#xff0c;在進行數據庫更新的過程之中&#xff0c;事務處理必須起作用&#xff0c;所以此時就可以編寫代理設計模式來完成。…

svm機器學習算法_SVM機器學習算法介紹

svm機器學習算法According to OpenCVs "Introduction to Support Vector Machines", a Support Vector Machine (SVM):根據OpenCV“支持向量機簡介”&#xff0c;支持向量機(SVM)&#xff1a; ...is a discriminative classifier formally defined by a separating …

6.3 遍歷字典

遍歷所有的鍵—值對 遍歷字典時&#xff0c;鍵—值對的返回順序也與存儲順序不同。 6.3.2 遍歷字典中的所有鍵 在不需要使用字典中的值時&#xff0c;方法keys() 很有用。 6.3.3 按順序遍歷字典中的所有鍵 要以特定的順序返回元素&#xff0c;一種辦法是在for 循環中對返回的鍵…

Google Guava新手教程

以下資料整理自網絡 一、Google Guava入門介紹 引言 Guavaproject包括了若干被Google的 Java項目廣泛依賴 的核心庫&#xff0c;比如&#xff1a;集合 [collections] 、緩存 [caching] 、原生類型支持 [primitives support] 、并發庫 [concurrency libraries] 、通用注解 [comm…

HTML DOM方法

querySelector() (querySelector()) The Document method querySelector() returns the first element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.Document方法querySelector()返回文檔中與…

leetcode 773. 滑動謎題

題目 在一個 2 x 3 的板上&#xff08;board&#xff09;有 5 塊磚瓦&#xff0c;用數字 1~5 來表示, 以及一塊空缺用 0 來表示. 一次移動定義為選擇 0 與一個相鄰的數字&#xff08;上下左右&#xff09;進行交換. 最終當板 board 的結果是 [[1,2,3],[4,5,0]] 謎板被解開。…

數據科學領域有哪些技術_領域知識在數據科學中到底有多重要?

數據科學領域有哪些技術Jeremie Harris: “In a way, it’s almost like a data scientist or a data analyst has to be like a private investigator more than just a technical person.”杰里米哈里斯(Jeremie Harris) &#xff1a;“ 從某種意義上說&#xff0c;這就像是數…

python 算術運算

1. 算術運算符與優先級 # -*- coding:utf-8 -*-# 運算符含有,-,*,/,**,//,% # ** 表示^ , 也就是次方 a 2 ** 4 print 2 ** 4 , aa 16 / 5 print 16 / 5 , aa 16.0 / 5 print 16.0 / 5 , a# 結果再進行一次floor a 16.0 // 5.0 print 16.0 // 5.0 , aa 16 // 5 print …

c語言編程時碰到取整去不了_碰到編程墻時如何解開

c語言編程時碰到取整去不了Getting stuck is part of being a programmer, no matter the level. The so-called “easy” problem is actually pretty hard. You’re not exactly sure how to move forward. What you thought would work doesn’t.無論身在何處&#xff0c;陷…

初創公司怎么做銷售數據分析_為什么您的初創企業需要數據科學來解決這一危機...

初創公司怎么做銷售數據分析The spread of coronavirus is delivering a massive blow to the global economy. The lockdown and work from home restrictions have forced thousands of startups to halt expansion plans, cancel services, and announce layoffs.冠狀病毒的…

leetcode 909. 蛇梯棋

題目 N x N 的棋盤 board 上&#xff0c;按從 1 到 N*N 的數字給方格編號&#xff0c;編號 從左下角開始&#xff0c;每一行交替方向。 例如&#xff0c;一塊 6 x 6 大小的棋盤&#xff0c;編號如下&#xff1a; r 行 c 列的棋盤&#xff0c;按前述方法編號&#xff0c;棋盤格…