Spring 源码之 SpringFactoriesLoader 类简介

类说明

SpringFactoriesLoader 是 Spring core 包中一个用于读取 classpath 下 META-INFO/spring.factories 文件中某个特定接口对应的实现类并完成实现类实例化的一个工具。该类是final 修饰的,即不能被继承,不能被修改。内部主要对外暴露了两个 public 类型的静态方法供使用方调用。

public final class SpringFactoriesLoader {
	//定义读取的文件路径,相对classpath
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
	
	//内部缓存,优先从缓存中查找实现类,缓存中没有在去读取文件获取
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();

    private SpringFactoriesLoader() {
    }

    public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
        Assert.notNull(factoryType, "'factoryType' must not be null");
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }
		//调用loadFactoryNames方法获取 factoryType类型的实现类
        List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
        if (logger.isTraceEnabled()) {
            logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
        }

        List<T> result = new ArrayList(factoryImplementationNames.size());
        Iterator var5 = factoryImplementationNames.iterator();

        while(var5.hasNext()) {
            String factoryImplementationName = (String)var5.next();
			//调用instantiateFactory 进行实现类的实例化创建,将实例化后的对象添加到result列表中
            result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
        }
		// 按优先级排序
        AnnotationAwareOrderComparator.sort(result);
        return result;
    }

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
		// 从 MultiValueMap 中查询key为 factoryType的实现类,如果不存在,则返回一个空列表
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		// 根据类加载器从缓存中找 MultiValueMap<接口, 实现类> 关系缓存
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
				//获取classpath下所有的 META-INF/spring.factories文件
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
				//循环遍历处理每个spring.factories文件
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
					//读取spring.factories 文件内容; spring.factories文件中存的是‘接口’和‘实现类’键值对,多个实现类英文逗号分隔
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();
					//遍历读取到的键值对
                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
						// 获取key,key为接口全路径名,即工厂类型
                        String factoryTypeName = ((String)entry.getKey()).trim();
						// 实现类全路径名数组
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;
						// 编辑实现类全路径名数组
                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
							//将实现类全路径名添加到以接口全路径名为key的result map中,result的value值为列表
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }
				//最后添加到缓存对象中,key为classLoader 对象
                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

    private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
        try {
            Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
            if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
				//校验实现类是否实现factoryType接口,不是则抛出异常
                throw new IllegalArgumentException("Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
            } else {
				//通过反射完成实现类无参构造函数的实例化
                return ReflectionUtils.accessibleConstructor(factoryImplementationClass, new Class[0]).newInstance();
            }
        } catch (Throwable var4) {
            throw new IllegalArgumentException("Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]", var4);
        }
    }
}

这个类的逻辑还是比较简单,虽然实现简单,但是在 Spring Boot 启动过程中起着重要作用,它可以很方便的完成 META-INFO/spring.factories 中配置的接口的实现类的装配,即完成对象的实例化。

单独如何使用?

由于 SpringFactoriesLoader 在 Spring core 包里,这里单独启一个项目,只引用code包,pom如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
    </dependencies>

在 src/test/resources/ 目录下添加 META-INFO/spring.factories文件,并添加如下图所示的属性

其中 com.jl.spring.task.Task 为实现 Runnable 接口的自定义实现类

package com.jl.spring.task;

public class Task implements Runnable {

    @Override
    public void run() {
        System.out.println("run task");
    }
}

在 src/test/java 目录下创建 SpringFactoriesLoaderTest 类,代码如下

import org.springframework.core.io.support.SpringFactoriesLoader;

import java.util.List;

public class SpringFactoriesLoaderTest {

    public static void main(String[] args) {
        List<Runnable> tasks = SpringFactoriesLoader.loadFactories(Runnable.class,
                SpringFactoriesLoaderTest.class.getClassLoader());
        tasks.forEach(Runnable::run);
    }

}

执行代码,会看到控制台输出:run task,说明 SpringFactoriesLoader.loadFactories 成功读取到了配置并完成了实现类的实例化。

注:spring版本为5.2.13

  • 18
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值