从0开始深入理解Spring-启动类构造
引言:
从本篇开始,打算深入理解Spring执行过程及原理,个人理解极有可能有偏差,评论区欢迎指正错误,下面开始进入正片内容。
ps: springboot版本使用2.4.8
Springboot项目启动时,是通过main方法中编写启动类的形式启动的,按照下面格式编写启动类
@SpringBootApplication
public class SpringFrameStudyApplication {public static void main(String[] args) {SpringApplication.run(SpringFrameStudyApplication.class);}
}
其核心为SpringApplication.run(SpringFrameStudyApplication.class)
方法,下面深入探讨该方法的执行
SpringApplication.java位于org.springframework.boot包下,是Springboot项目启动的核心类。点击run()方法。进入该方法
这里run方法不做过多解析,下篇会详解run方法的具体执行过程
SpringApplication.java
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class<?>[] { primarySource }, args);}public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {// 在这里创建了SpringApplication对象,并执行run方法。执行完毕后返回配置好的上下文对象ConfigurableApplicationContextreturn new SpringApplication(primarySources).run(args);}// 构造方法public SpringApplication(Class<?>... primarySources) {this(null, primarySources);}// SpringApplication核心构造方法public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {// 资源加载器: 如果按照上述方法进行构造时,为nullthis.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// webApplicationType属性用于判断运行容器: 为Servlet还是Reactive。Reactive为响应式的架构: SpringWebFlexthis.webApplicationType = WebApplicationType.deduceFromClasspath();// 这里重点介绍下。从SpringFactories中获得Boot的注册器及初始化器等相关信息并将springfatory中的信息初始化至缓存中的this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();// 设置Application上下文初始化器 相关属性(赋值操作)setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 设置应用监听初始化器 相关属性(赋值操作)setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 赋值 jvm线程栈中 main方法栈所在类this.mainApplicationClass = deduceMainApplicationClass();}
这里避免类代码过长过重,拆分两部分进行代码讲解。下面这一部分介绍getBootstrapRegistryInitializersFromSpringFactories()
是如何从MATE-INFO/spring.factory中获取相关属性
SpringApplication.java
private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();// 核心方法,获得Bootstrapper类有关的SpringFactory实例getSpringFactoriesInstances(Bootstrapper.class).stream().map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize)).forEach(initializers::add);// 获得BootstrapRegistryInitializer类有关的SpringFactory实例initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));return initializers;}public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {this.initializers = new ArrayList<>(initializers);}public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {this.listeners = new ArrayList<>(listeners);}/*** 根据类型获得SpringFacotries实例* @param type*/private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {return getSpringFactoriesInstances(type, new Class<?>[] {});}/*** 根据类型获得SpringFacotries实例* @param type 类类型* @param parameterTypes 参数类型* @param args 构造方法的参数*/private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {// 这里getClassLoader()为内部的一个方法ClassLoader classLoader = getClassLoader();// 根据传入的类获得SpringFactories中的限定名称Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 根据名称集合创建实例List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);// 按照order进行排序AnnotationAwareOrderComparator.sort(instances);return instances;}public ClassLoader getClassLoader() {if (this.resourceLoader != null) {// 正常默认启动时,resourceLoader为空return this.resourceLoader.getClassLoader();}// 默认返回当前主线程return ClassUtils.getDefaultClassLoader();}
SpringFactoriesLoader.java
// 获取spring.factories中的所在位置public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse = classLoader;if (classLoaderToUse == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();// 加载所有springfactories的实现类并 根据factoryTypeName获得该实现类的名称return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {// 从缓存中获取已经加载的类 名称Map<String, List<String>> result = cache.get(classLoader);if (result != null) {return result;}// 如果没有result = new HashMap<>();try {// 类加载器中获得spring.factories的所在url地址Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);// 加载resource资源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());}}}// 将其列表去重并修改为不可修改的集合result.replaceAll((factoryType, implementations) -> implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));// 加入缓存中 key为classLoadercache.put(classLoader, result);}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);}return result;}
构造SpringApplication实例的过程实际上是完成了spring.factories文件的扫描,并将扫描好的factories配置放入缓存中(key: className, values: List names)。按照需要去获取设置 上下文、监听等 实现类。