springboot中getSpringFactoriesInstances源码的示例分析

这篇文章主要介绍了springboot中getSpringFactoriesInstances源码的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

网站建设哪家好,找创新互联公司!专注于网页设计、网站建设、微信开发、小程序定制开发、集团企业网站建设等服务项目。为回馈新老客户创新互联还提供了石泉免费建站欢迎大家使用!

 

一、概述及流程图

在springboot启动过程中,getSpringFactoriesInstances这个方法很重要,启动的时候使用该方法从classpath上所有jar包中找出对应的META-INF/spring.factorys属性文件,并将其中的初始化器和监听器加载并实例化,应用于更进一步的初始化工作。其工作流程图如下:

springboot中getSpringFactoriesInstances源码的示例分析  
image
 

二、源码解析

让我们跟着流程图和时序图一步步窥视其中的奥妙:

springboot中getSpringFactoriesInstances源码的示例分析  
image
  1. 调用getSpringFactoriesInstances()方法
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
 //资源加载器
 this.resourceLoader = resourceLoader;
 //断言,传入参数不能为空,即必须传入启动类
 Assert.notNull(primarySources, "PrimarySources must not be null");
 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
 //通过类路径推断服务类型
 this.webApplicationType = WebApplicationType.deduceFromClasspath();
 //1.加载初始化器并实例化,10.并赋值给initializers
 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
 //同上,监听器
 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
 //推断应用主类
 this.mainApplicationClass = deduceMainApplicationClass();
}
 
  1. 获取类加载器和调用loadFactoryNames()方法及对返回结果进行初始化以及排序
private  Collection getSpringFactoriesInstances(Class type) {
 return getSpringFactoriesInstances(type, new Class[] {});
}

private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
 //2. 获取类加载器
 ClassLoader classLoader = getClassLoader();
 // Use names and ensure unique to protect against duplicates
 //3. 调用loadFactoryNames方法,并使用set对其返回结果进行去重处理
 Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
 //9. 实例化初始化器
 List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
 //9. 对实例化的结果进行排序
 AnnotationAwareOrderComparator.sort(instances);
 return instances;
}

//该方法主要是通过反射实例化初始化器
private  List createSpringFactoriesInstances(Class type, Class[] parameterTypes,
   ClassLoader classLoader, Object[] args, Set names) {
  List instances = new ArrayList<>(names.size());
  for (String name : names) {
   try {
    Class instanceClass = ClassUtils.forName(name, classLoader);
    Assert.isAssignable(type, instanceClass);
    Constructor constructor = instanceClass.getDeclaredConstructor(parameterTypes);
    T instance = (T) BeanUtils.instantiateClass(constructor, args);
    instances.add(instance);
   }
   catch (Throwable ex) {
    throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
   }
  }
  return instances;
 }
 
  1. 查询缓存和读取META-INFO/spring.factorys文件key-value值,并对value值进行处理
public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
  String factoryClassName = factoryClass.getName();
  // 返回初始化器的value值
  return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
 }

 private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
  MultiValueMap result = //查询缓存,如果有就返回,没有就加载
  cache.get(classLoader);
  if (result != null) {
   return result;
  }

  try {
      //通过类加载器加载所有jar包中包含META-INFO/spring.factorys的文件资源路径
   Enumeration urls = (classLoader != null ?
     classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
     ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
   result = new LinkedMultiValueMap<>();
   while (urls.hasMoreElements()) {
    URL url = urls.nextElement();
    UrlResource resource = new UrlResource(url);
    //实例化properties对象,并加载路径中的spring.factorys文件内容
    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    for (Map.Entry entry : properties.entrySet()) {
     String factoryClassName = ((String)
     //获取key值
     entry.getKey()).trim();
     //对value值进行都好拆分处理
     for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
        //将key和value值存入result中 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);
  }
 }

感谢你能够认真阅读完这篇文章,希望小编分享的“springboot中getSpringFactoriesInstances源码的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!


当前题目:springboot中getSpringFactoriesInstances源码的示例分析
转载注明:http://ybzwz.com/article/ipgsdh.html