springboot启动原理篇一:SpringApplication的初始化
SpringApplication的初始化
// 总览初始化实现
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
-
进入SpringApplication构造器
SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)
中,首先SpringApplication.resourceLoader赋值nullthis.resourceLoader = resourceLoader;
-
将主启动类加入到 SpringApplication.primarySources
// 存储主要的应用程序源,即用于启动 Spring Boot 应用程序的主要配置类或主类,这个主类通常是我们springboot项目的启动类 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
-
判断应用类型,并赋值给 SpringApplication.webApplicationType
// 获取应用程序的 Web 应用类型,并赋值给SpringApplication.webApplicationType this.webApplicationType = WebApplicationType.deduceFromClasspath();
-
deduceFromClasspath()方法源码如下
String[] SERVLET_INDICATOR_CLASSES = {"javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"}; String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet"; String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler"; String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer"; static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) // 判断DispatcherHandler类是否存在于类路径中 && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) // 判断DispatcherServlet类是否存在于类路径中 && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { // 判断ServletContainer类是否存在于类路径中 return WebApplicationType.REACTIVE; // 返回响应式的spring应用 } for (String className : SERVLET_INDICATOR_CLASSES) { // 判断Servlet和ConfigurableWebApplicationContext是否存在于类路径中 if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET;// 基于servlet的spring应用 }
-
-
调用getSpringFactoriesInstances方法,传入 BootstrapRegistryInitializer.class作为参数将 并赋值给 SpringApplication.bootstrapRegistryInitializers
// 初始化引导注册表(Bootstrap Registry)的初始化器列表 this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
-
getSpringFactoriesInstances()源码
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); } private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // 将list集合转换为set Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 实例化所有names中的类,装到list中返回 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
-
SpringFactoriesLoader.loadFactoryNames(type, classLoader)源码
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); // loadSpringFactories返回的是所有配置,调用getOrDefault,从配置中抽取对应的key-value并返回value(这个value是个list) return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }
-
loadSpringFactories源码
// 加载spring.factories文件中的全部配置(代码看一下即可,不必深究) 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 { //读取META-INFO/spring.factories文件中的配置 Enumeration<URL> 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; }
-
-
createSpringFactoriesInstances()源码
// 由传递可知,parameterTypes是个空集合,也就意味着获取的类的构造器是无参构造器(这里需要你拥有Java反射的知识) private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { // 初始化一个list,用于存放实例对象 List<T> instances = new ArrayList<>(names.size()); // 遍历list,这个names就是getSpringFactoriesInstances中调用此方法传入的类集合 for (String name : names) { try { 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);// 将实例化对象加入到instances中 } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances;// 返回存放实例对象的list }
-
-
-
调用getSpringFactoriesInstances方法,传入ApplicationContextInitializer.class作为参数 并赋值给SpringApplication.initializers
// 获取所有实现了 ApplicationContextInitializer 接口的初始化器实例,并将它们设置为应用程序的初始化器(initializers)。这些初始化器在应用程序启动时执行特定的初始化逻辑,例如配置属性源、设置环境变量等 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
-
调用getSpringFactoriesInstances方法,传入 ApplicationListener.class作为参数将 并赋值给 SpringApplication.Listeners
// 获取所有实现了 ApplicationListener 接口的监听器实例,并将它们设置为应用程序的监听器(listeners)。这些监听器用于监听和响应应用程序的各种事件,例如应用程序启动事件、环境准备事件等 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
-
将主启动类赋值给 SpringApplication.mainApplicationClass
// 推断并设置应用程序的主类(main class),用于识别应用程序的入口点 this.mainApplicationClass = deduceMainApplicationClass();
总结
SpringApplication的初始化工作主要干了以下几件事
- 为resourceLoader赋值为null,
- 设置primarySources为当前项目运行启动类
- 判断应用类型,并赋值给webApplicationType
- 实例化“初始化引导注册表(bootstrapRegistryInitializers)”的初始化器列表,这个列表中存的是实例化的实现了BootstrapRegistryInitializer.class接口的类的对象。
- 实例化“应用程序的初始化器(Initializer)”的初始化器列表,这个列表中存的是实例化的实现了ApplicationContextInitializer.class接口的类的对象
- 实例化“监听器(listeners)”的列表,这个列表中存的是实例化的实现了ApplicationListener.class接口的类的对象
- 为mainApplicationClass属性赋值,值为应用程序的入口点,一般是我们springboot项目的启动类
最近忙着面试,时间仓促,就先把执行流程先捋一遍,后面有空了,再详细解释每步的作用和意义,再画个流程图来解释整个流程
本文来自博客园,作者:勤匠,转载请注明原文链接:https://www.cnblogs.com/JarryShu/articles/18081917
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现