简介

springboot的各个依赖包下,很多都有META-INF/spring.factories这个文件。例如

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.test.springbootdemo.usultestdemo.configration.propertiespropertysource.myconfiguretation.MyCommandRunable,\
com.test.springbootdemo.usultestdemo.configration.propertiespropertysource.myconfiguretation.MyDisposableBeanConfigureration,\
com.test.springbootdemo.usultestdemo.configration.propertiespropertysource.myconfiguretation.MyInitBeanConfigureration,\
com.test.springbootdemo.usultestdemo.configration.propertiespropertysource.myconfiguretation.MyApplicationContextAware

通过内容可以知道spring.factories定义了一些对象。实际上spring.factories的作用就是做上下文初始化,加载配置文件中的bean到Ioc容器,加载配置项等。springboot执行时或扫描所有的META-INF/spring.factories的内容,会将classLoader加载类路径下的所有spring.factories的配置内容,loadSpringFactories方法将返回一个key=接口名,value=实现类集合的Map结构。

spring.factories加载流程

在我们的springboot项目中执行run()方法后,就开始进入内容的初始化过程。

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
   //获取所有的org.springframework.boot.SpringApplicationRunListeners实现类,这里我们也可以使用spring.factories自定义实现类。
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting();
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
     //自定义监听器加载配置信息和系统环境变量
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
      configureIgnoreBeanInfo(environment);
      Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      //获取所有spring.factories自定义实现,根据type值找到对应的 class  的全限定名称列表
      exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
     //执行自定义spring.fatories中的类(Bean初始化类,环境变量初始化类)的指定方法
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
      listeners.started(context);
      //一些程序启动就要执行的的任务,包括spring.fatories中定义的key为EnableAutoConfiguration, j接口CommandLineRunner的实现类。
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, listeners, exceptionReporters, ex);
      throw new IllegalStateException(ex);
   }
   listeners.running(context);
   return context;
}

     对象获取到并实例化之后之后,refreshContext(context);会执行自定义spring.fatories中的类(Bean初始化类,环境变量初始化类)的指定方法。callRunners(context, applicationArguments);一些程序启动就要执行的的任务,包括spring.fatories中定义的key为EnableAutoConfiguration, 接口CommandLineRunner的实现类等。

getSpringFactoriesInstances和createSpringFactoriesInstances方法。

public class SpringApplication {
   private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {});
   }
    // 获取Spring工厂
   private <T> Collection<T> getSpringFactoriesInstances(Class<T> 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 中定义的父节点
       Set<String> names = new LinkedHashSet<>(
         SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 内部循环初始化 names的构造函数,获取实例实例对象
       List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
         classLoader, args, names);
       AnnotationAwareOrderComparator.sort(instances);
       return instances;
   }
   // 创建Spring工厂实例
   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 {
            // 加载该类,通过指定的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;
}
}

SpringFactoriesLoader类是解析所有Spring.factories实现。方法主要是loadFactoryNames()和loadSpringFactories()

public abstract class SpringFactoriesLoader {
   public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
   private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
    // 加载工厂
   public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
      // 获取类名称(图4)
      String factoryClassName = factoryClass.getName();
      // 根据类名称获取需要加载的工厂类名称
      return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
   }
    // 通过加载所有 classpath 下面的 META-INF/spring.factories文件,扫描加载类
   private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        // 从cache获取实例的结果集 当是Null表示当前的cache是空的;cache 实现 new ConcurrentReferenceHashMap<>()
      MultiValueMap<String, String> result = cache.get(classLoader);
      if (result != null) {
         return result;
      }
      try {
          // 获取所有 classpath 下面的 META-INF/spring.factories 中的资源 urls
          // 当classLoader为非空的时候调用getResouurces方法获取
          // 当classLoader为空的时候调用ClassLoader.getSystemResouurces方法获取
         Enumeration<URL> urls = (classLoader != null ?
               classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
               ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
         result = new LinkedMultiValueMap<>();
          // 循环处理 urls中的元素,获取元素 
         while (urls.hasMoreElements()) {
             // 获取元素 url地址
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
             // 解析文件 把文件变成配置属性
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
             // 循环解析并把结果放入result
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                // 类名列表
               List<String> factoryClassNames = Arrays.asList(
                     StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));

               //记录所有的key和对应的value集合
               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);
      }
   }
}

   在获取到所有的接口之后,就会调用getSpringFactoriesInstances()创建接口的实现类。

   spring.factories就像是工厂一样配置了大量的接口对应的实现类,我们通过这些配置 + 反射处理就可以拿到相应的实现类。这种类似于插件式的设计方式,只要引入对应的jar包,那么对应的spring.factories就会被扫描到,对应的实现类也就会被实例化,如果不需要的时候,直接把jar包移除即可。

 

https://www.cnblogs.com/zhangjianbin/p/6322476.html

https://www.cnblogs.com/huojg-21442/articles/12335457.html

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐