如何理解springboot2.0.6中META-INF/spring.factories通过系统加载类获取对应的class的全限定名称
这篇文章将为大家详细讲解有关如何理解springboot2.0.6中META-INF/spring.factories通过系统加载类获取对应的class的全限定名称,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
专注于为中小企业提供网站设计、成都网站设计服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业灌云免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了近1000家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
在 SpringBoot中是通过getSpringFactoriesInstances(Class
源码解析
getSpringFactoriesInstances()方法
public class SpringApplication { privateCollection getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class>[] {}); } // 获取Spring工厂 private Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { // 获取ClassLoader ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates // 定义class数组,即返回值 names 是所有 classpath 下面的 META-INF/spring.factories 中定义的父节点(图2) Set names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 内部循环初始化 names的构造函数,获取实例实例对象(图2) List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } // 创建Spring工厂实例 private List createSpringFactoriesInstances(Class type, Class>[] parameterTypes, ClassLoader classLoader, Object[] args, Set names) { List instances = new ArrayList<>(names.size()); // 循环处理names的值 for (String name : names) { try { //( 图3) //通过指定的classloader加载对应的类获取对应的Class对象 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; } }
getSpringFactoriesInstances方法通过SpringFactoriesLoader类的loadFactoryNames方法获取系统加载类去所有classpath下面的 META-INF/spring.factories文件中获取对应的 class 的全限定名称结合,在执行createSpringFactoriesInstances方法遍历该集合对进行循环创建实例。然后返回实例对象集合。
names 为获取所有 classpath 下面的 META-INF/spring.factories文件中applicationContextInitializer相关加载类的值
instances 为遍历names创建的Spring工厂实例列表
以getSpringFactoriesInstances(ApplicationContextInitializer.class)为例进行debug分析
图1-1和图1-2标记出所有classpath下面的 META-INF/spring.factories文件中ApplicationContextInitializer.class对应的所有全限定名称
(图1-1)
(图1-2)
(图2)根据类名“applicationContextInitializer”获取 spring.factories文件中applicationContextInitializer相关的工厂类,并进行初始化)
( 图3) 根据类名进行初始化创建实例
在SpringApplication类的getSpringFactoriesInstances方法中进入SpringFactoresLoader类的loadFactoryNames方法
public abstract class SpringFactoriesLoader { public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; private static final Map> cache = new ConcurrentReferenceHashMap<>(); // 加载工厂 public static List loadFactoryNames(Class> factoryClass, @Nullable ClassLoader classLoader) { // 获取类名称(图4) String factoryClassName = factoryClass.getName(); // 根据类名称获取需要加载的工厂类名称 return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } // 通过加载所有 classpath 下面的 META-INF/spring.factories文件,扫描加载类,(图8) private static Map > loadSpringFactories(@Nullable ClassLoader classLoader) { // 从cache获取实例的结果集 当是Null表示当前的cache是空的;cache 实现 new ConcurrentReferenceHashMap<>() MultiValueMap result = cache.get(classLoader); if (result != null) { return result; } try { // 获取所有 classpath 下面的 META-INF/spring.factories 中的资源 urls(图5) // 当classLoader为非空的时候调用getResouurces方法获取 // 当classLoader为空的时候调用ClassLoader.getSystemResouurces方法获取 Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); // 循环处理 urls中的元素,获取元素 while (urls.hasMoreElements()) { // 获取元素 url地址(图6) URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); // 解析文件 把文件变成配置属性(图6) Properties properties = PropertiesLoaderUtils.loadProperties(resource); // 循环解析并把结果放入result for (Map.Entry, ?> entry : properties.entrySet()) { // 类名列表(图7) List factoryClassNames = Arrays.asList( StringUtils.commaDelimitedListToStringArray((String) entry.getValue())); result.addAll((String) entry.getKey(), factoryClassNames); } } // 缓存类加载器和文件解析器的结果集 cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } }
以loadFactoryNames(ApplicationContextInitializer.class,classLoader)为例进行debug分析
(图4)获取class全称
(图5) 获取所有 classpath 下面的 META-INF/spring.factories文件的urls
(图6) 获取spring.factories文件的具体位置及文件中的内容)(图7) 获取spring.factories文件内容中的对应类列表
( 图8)
总结
通过classLoader加载classpath下面的META-INF/spring.factories文件,获取文件信息解析成配置属性存入结果集中,在根据type的全限定名称,从结果集中获取type对应的结果集。循环便利该结果集根据“全限定名称”创建实例。对实例集合排序后返回
关于如何理解springboot2.0.6中META-INF/spring.factories通过系统加载类获取对应的class的全限定名称就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
网页标题:如何理解springboot2.0.6中META-INF/spring.factories通过系统加载类获取对应的class的全限定名称
URL分享:http://pwwzsj.com/article/ihcioe.html