一.SpringBoot的自动装配
1.@Import(AutoConfigurationImportSelector.class)
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered
2.DeferredImprotSelector
public interface DeferredImportSelector extends ImportSelector
- DeferredImprotSelector是ImprotSelector的一种扩展
- 在处理完所有的 @Configuration类型的Bean之后运行
- 当导入@Conditional时,这种类型选择器特别有用
- 实现还可以扩展Ordered接口,或使用@Order注解指示对其DeferredImportSelector优先级
总结:
- 执行时机:在@configuration注解中其他逻辑被处理完毕之后(包括对@ImprotResource,@Bean)再执行
- DeferredImportSelector执行时机比ImprotSelector更晚
中其
二.AutoConfigurationImportSelector
的核心
@override
public String[] selectImports(AnnotationMetadata annotationMetadata){
if(!isEmabled(annotationMetadata)){
return NO_IMPORTS;
}
AutoconfigurationMetadata autoConfigurationMetadata=AutoconfigurationMetadataLoder.loadMetadata(this.beanClassLoader);
// 加载自动配置类
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
三.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata)
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata){
if(!isEnabled(annotationMetadata)){
return EMPTY_ENTRY;
}
AnnotationAttributes attributes=getAttributes(annotationMetadata);
//核心-加载候选的自动配置类
List<String> configurations=getCandidateConfigurations(annotationMetadata, attribute);
configurations=removeDuplicates(configurations);
Set<String> exclusions=getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
四.SpringBoot使用的工厂机制
1.java的SPI
- SPI全称Service Provider Interface
- jdk内置服务提供发现机制---动态替换发现的机制
2.SpringFramework的SpringFactoriesLoader
loadFactoryNames方法:
public static List<String> loadFactoryNames(Class<?> factoryClass,@Nullable ClassLoader classLoader){
String factoryClassName = factoryClass.getName();
return laodSpringFactories(classLoader).getOrDefault(factoryClassName,Collections.emptyList());
}
3.loadSpringFactories的实现,其中有缓存的写法值得学习
public static final String FACTORIES_RESOURCE_LOCATION="META-INF/spring.factories";
private static final Map<ClassLoader,MultiValueMap<String, String>> cache=new ConcurrentReferenceHashMap<>();
private static Map<String,List<String>> loadSpringFactories(@Nullable ClassLoader classLoader){
Map<ClassLoader,MultiValueMap<String, String>> result=cache.get(classLoader);
if(result!=null){
return result;
}
try{
//获取当前 classpath 下所有jar包中有的 spring.factories 文件,并将它们加载到内存中
Enumeration<URL> urls=(classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
//每一个文件,并用 Properties 方式加载文件,之后把这个文件中每一组键值对都加载出来,放入 MultiValueMap 中
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()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}catch (IOException ex){
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION +"]",ex );
}
}
五.总结
- AutoconfigurationImprotSelector 配合SpringFactoriseLoader可加载“META-INF/spring.factories”中配置@EnableAutoconfiguration对应的自动配置类
- deferredImportSelector的执行时机比ImprotSelector更晚
- SpringFramework 实现了自己的SPI技术,相比较于Java原生的SPI更灵活。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。