微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SpringBoot学习笔记三自动装配

一.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更灵活。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐