springboot中getSpringFactoriesInstances源码的示例分析

发布时间:2021-11-24 17:44:25 作者:小新
来源:亿速云 阅读:188

这篇文章主要介绍了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 <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
 return getSpringFactoriesInstances(type, new Class<?>[] {});
}

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

//该方法主要是通过反射实例化初始化器
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
   ClassLoader classLoader, Object[] args, Set<String> names) {
  List<T> 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<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
  String factoryClassName = factoryClass.getName();
  // 返回初始化器的value值
  return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
 }

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

  try {
      //通过类加载器加载所有jar包中包含META-INFO/spring.factorys的文件资源路径
   Enumeration<URL> 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源码的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

推荐阅读:
  1. React中setState源码的示例分析
  2. Bootstrap中Scrollspy源码的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot

上一篇:如何理解Vue的监听属性

下一篇:Protobuf工具在C#中的使用方法是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》