在之前的一些文章中,我們提到過從spring.factories中找出key為XXX的類。比如@EnableAutoConfiguration注解對應的EnableAutoConfigurationImportSelector中的selectImport方法會在spring.factories文件中...
在之前的一些文章中,我們提到過從spring.factories中找出key為XXX的類。比如@EnableAutoConfiguration注解對應的EnableAutoConfigurationImportSelector中的selectImport方法會在spring.factories文件中找出key為EnableAutoConfiguration對應的值。
這些類都是自動化配置類:
// 這個spring.factories文件在spring-boot-autoconfigure模塊的 META-INF/spring.factories中
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.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
......
代碼的實現,EnableAutoConfigurationImportSelector的selectImport方法:
@Override
public String[] selectImports(AnnotationMetadata metadata) {
try {
// 獲取注解的屬性
AnnotationAttributes attributes = getAttributes(metadata);
// 讀取spring.factories屬性文件中的數據
List<String> configurations = getCandidateConfigurations(metadata,
attributes);
// 刪除重復的配置類
configurations = removeDuplicates(configurations);
// 找到@EnableAutoConfiguration注解中定義的需要被過濾的配置類
Set<String> exclusions = getExclusions(metadata, attributes);
// 刪除這些需要被過濾的配置類
configurations.removeAll(exclusions);
// 配置類做排序
configurations = sort(configurations);
// 記錄配置類的處理信息到ConditionEvaluationReport中
recordWithConditionEvaluationReport(configurations, exclusions);
// 返回最終得到的自動化配置類
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 調用SpringFactoriesLoader的loadFactoryNames靜態方法
// getSpringFactoriesLoaderFactoryClass方法返回的是EnableAutoConfiguration類對象
return SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
// 解析出properties文件中需要的key值
String factoryClassName = factoryClass.getName();
try {
// 常量FACTORIES_RESOURCE_LOCATION的值為META-INF/spring.factories
// 使用類加載器找META-INF/spring.factories資源
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));
// 找出key為參數factoryClass類對象對應的全名稱對應的值
String factoryClassNames = properties.getProperty(factoryClassName);
// 以逗號分隔添加到結果集中
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);
}
}
Spring Framework內部使用一種工廠加載機制(Factory Loading Mechanism)。這種機制使用SpringFactoriesLoader完成,SpringFactoriesLoader使用loadFactories方法加載并實例化從META-INF目錄里的spring.factories文件出來的工廠,這些spring.factories文件都是從classpath里的jar包里找出來的。
spring.factories文件是以Java的Properties格式存在,key是接口或抽象類的全名、value是以逗號 “ , “ 分隔的實現類,比如:
example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
其中example.MyService是接口的全名,
example.MyServiceImpl1和example.MyServiceImpl2是這個接口的兩種實現。
可通過SpringFactoriesLoader完成:
List<String> classes = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, this.getClass().getClassLoader());
classes.forEach(clazz -> {
System.out.println("==== " + clazz);
});
# 總結
工廠加載機制是Spring內部提供的一個約定俗成的加載方式。只需要在模塊的META-INF目錄下定義Properties格式的spring.factories文件,這個Properties格式的文件中的key是接口或抽象類的全名,value是以逗號 “ , “ 分隔的實現類。
SpringBoot中的autoconfigure模塊中的spring.factories就存在于META-INF目錄下:
├── META-INF
│ ├── MANIFEST.MF
│ ├── additional-spring-configuration-metadata.json
│ ├── maven
│ │ └── org.springframework.boot
│ │ └── spring-boot-autoconfigure
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── spring-configuration-metadata.json
│ └── spring.factories
├── org
│ └── springframework
│ └── boot
│ └── autoconfigure
│ ├── AbstractDependsOnBeanFactoryPostProcessor.class
....
而且也定義了一些配置,比如自動化配置信息:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=...
應用初始化器:
org.springframework.context.ApplicationContextInitializer=...
應用監聽器:
org.springframework.context.ApplicationListener=...
模板可用提供器:
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=...
等等。
我們只需要遵守這個機制并在對應的文件中寫出需要加載的接口和實例即可,或者自己使用SpringFactoriesLoader實現加載。
來源:http://fangjian0423.github.io/2017/06/05/springboot-factory-loading-mechanism
來源:本文內容搜集或轉自各大網絡平臺,并已注明來源、出處,如果轉載侵犯您的版權或非授權發布,請聯系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內容的準確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負責,僅作分享之用,文章版權及插圖屬于原作者。
Copyright?2013-2024 JSedu114 All Rights Reserved. 江蘇教育信息綜合發布查詢平臺保留所有權利
蘇公網安備32010402000125
蘇ICP備14051488號-3技術支持:南京博盛藍睿網絡科技有限公司
南京思必達教育科技有限公司版權所有 百度統計