栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Boot启动主流程-构造方法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Boot启动主流程-构造方法

版本说明

Spring Boot:【2.4.6】

Spring: 【5.3.7】

SpringApplication构造方法主流程

新建一个简单的springboot项目,只导入web模块。

从入口开始分析

@SpringBootApplication
public class SpringboothelloApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringboothelloApplication.class, args);
    }
}

先不用管注解@SpringBootApplication的事,点开run方法

# SpringApplication.java
public static ConfigurableApplicationContext run(Class primarySource, String... args) {
   return run(new Class[] { primarySource }, args);
}

继续跟run方法

public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) {
   return new SpringApplication(primarySources).run(args);
}

这里new了一个SpringApplication,并且调用该实例的run方法

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   this.primarySources = new linkedHashSet<>(Arrays.asList(primarySources));
   // 决议web应用类型
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   // 获取BootstrapRegistryInitializer并设置
   this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
   // 获取ApplicationContextInitializer并设置
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   // 获取ApplicationListener并设置
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   // 通过栈调用链决议主类
   this.mainApplicationClass = deduceMainApplicationClass();
}

上述方法里通过调用getSpringFactoriesInstances获取相应的工厂实例,这块是个比较重要的点。

	private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
         // 第一次load,从spring.factories下加载工厂名字,放到cache中,之后从cache读取
		Set names = new linkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 通过反射实例化
		List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

上面代码出现了Spring框架的一个比较重要的类SpringFactoriesLoader,负责从classpath下的meta-INF/spring.factories下加载和实例化指定类型的工厂。

General purpose factory loading mechanism for internal use within the framework.
SpringFactoriesLoader loads and instantiates factories of a given type from “meta-INF/spring.factories” files which may be present in multiple JAR files in the classpath. The spring.factories file must be in Properties format, where the key is the fully qualified name of the interface or abstract class, and the value is a comma-separated list of implementation class names. For example:
example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
where example.MyService is the name of the interface, and MyServiceImpl1 and MyServiceImpl2 are two implementations.

SpringFactoriesLoader内部持有一个cache,只读取一次,多次load的时候直接从cache读取

	static final Map>> cache = new ConcurrentReferenceHashMap<>();

关键方法如下,很简单,先从cache读,没有则从FACTORIES_RESOURCE_LOCATION加载资源,解析后放到cache中。

private static Map> loadSpringFactories(ClassLoader classLoader) {
   Map> result = cache.get(classLoader);
   if (result != null) {
      return result;
   }

   result = new HashMap<>();
   try {
      Enumeration urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
      while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
         UrlResource resource = new UrlResource(url);
         Properties properties = PropertiesLoaderUtils.loadProperties(resource);
         for (Map.Entry entry : properties.entrySet()) {
            String factoryTypeName = ((String) entry.getKey()).trim();
            String[] factoryImplementationNames =
                  StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
            for (String factoryImplementationName : factoryImplementationNames) {
               result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                     .add(factoryImplementationName.trim());
            }
         }
      }

      // Replace all lists with unmodifiable lists containing unique elements
      result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
            .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
      cache.put(classLoader, result);
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
            FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
   return result;
}
End

构造方法内完成的事情

    决议web应用类型获取BootstrapRegistryInitializer并设置获取ApplicationContextInitializer并设置获取ApplicationListener并设置通过栈调用链决议主类

其中比较关键的调用链路

下图是具体代码的执行流程

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/731690.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号