springboot的启动流程相当复杂,我们需要先把控整体流程,后面会有若干文章一一讲解springboot启动流程中的重要的细节,springboot的启动经过了一些一系列的处理,我们先看看整体过程的流程图
篇幅有限,我们这里先聊聊实例化SpringApplication的过程:
/*** SpringApplication构造器* @param resourceLoader* @param primarySources*/public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.sources = new LinkedHashSet();this.bannerMode = Banner.Mode.CONSOLE;this.logStartupInfo = true;this.addCommandLineProperties = true;this.addConversionService = true;this.headless = true;this.registerShutdownHook = true;this.additionalProfiles = new HashSet();this.isCustomEnvironment = false;this.lazyInitialization = false;this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));//设置应用类型this.webApplicationType = WebApplicationType.deduceFromClasspath();//设置初始化器this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));//设置监听器this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));//获取主类class对象this.mainApplicationClass = this.deduceMainApplicationClass();}
获取应用程序的类型
首先是这个方法
this.webApplicationType = WebApplicationType.deduceFromClasspath();
我们进入这个方法就知道,首先判断是否响应式类型,如果不是就是一般的servlet类型的应用
static WebApplicationType deduceFromClasspath() {if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {return REACTIVE;} else {// private static final String[] SERVLET_INDICATOR_CLASSES =// new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};//这里两个都是存在的类型String[] var0 = SERVLET_INDICATOR_CLASSES;int var1 = var0.length;for(int var2 = 0; var2 < var1; ++var2) {String className = var0[var2];if (!ClassUtils.isPresent(className, (ClassLoader)null)) {return NONE;}}return SERVLET;}}
加载所有的初始化器
这里加载的初始化器是springboot自带初始化器,从 META-INF/spring.factories 配置文件中加载的,那么这个文件在哪呢?自带有2个,分别在源码的jar包的 spring-boot-autoconfigure 项目 和 spring-boot 项目里面各有一个
/*** SpringApplication的getSpringFactoriesInstances* 这个是共用的方法* @param type 类型,一般都是接口类型* @param parameterTypes 参数类型,在获取初始化器的时候是一个空数组* @param args 初始化类* @return* @param <T> 返回的所有实例对象*/private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {//获取当前class加载器ClassLoader classLoader = this.getClassLoader();//加载所有的对象名称,全限定类名Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));//利用反射,初始化找的所有对象List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);//排序对象AnnotationAwareOrderComparator.sort(instances);return instances;}
加载配置文件,然后放到缓存中,缓存是一个map类型,key是当前类加载器,value是一个多值的map。
/**** @param classLoader 类加载器* @return 返回是 key = v1,v2 多值map*/private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {//先从缓存中去取k-v,key是当前类加载器,value又是一个key -value,是一个MultiValueMap类型,一个key对应多个valueMultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);if (result != null) {return result;} else {try {//扫描所有META-INF/spring.factories的配置文件Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");MultiValueMap<String, String> result = new LinkedMultiValueMap();//遍历找的所有文件while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);//转换成属性对象Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator<?> it = properties.entrySet().iterator();//遍历文件中所有键值对 格式: key = v1,v2,v3while(it.hasNext()) {Map.Entry<?, ?> entry = (Map.Entry)it.next();String factoryTypeName = ((String)entry.getKey()).trim();String[] strings = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());int length = strings.length;for(int i = 0; i < length; ++i) {String factoryImplementationName = strings[i];result.add(factoryTypeName, factoryImplementationName.trim());}}}//缓存所有已经加载的 key = v1,v2,v3cache.put(classLoader, result);return result;} catch (IOException var13) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);}}}
我们讲接口名称com.xxx.xxx去缓存获取,然后得到一个实现接口的类名的列表,通过列表,实例化所有对象,下面我们看实例化的所有逻辑
/*** 实例化spring.factories里面的实现类* @param type 类型* @param parameterTypes 类型参数,可以空* @param classLoader* @param args 参数 可以空* @param names 实例的名称* @return 实例化后的对象列表* @param <T>*/private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {List<T> instances = new ArrayList<>(names.size());Iterator<String> it = names.iterator();while(it.hasNext()) {String name = it.next();try {Class<?> instanceClass = ClassUtils.forName(name, classLoader);Assert.isAssignable(type, instanceClass);Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);T instance = BeanUtils.instantiateClass(constructor, args);instances.add(instance);} catch (Throwable var12) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);}}return instances;}
至此,为SpringApplication对象设置初始化器完毕
加载所有的监听器
代码如下:
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
从代码也可以看出,和获取初始化器逻辑是一模一样的,这个就不多说了。
获取主类class对象
this.mainApplicationClass = this.deduceMainApplicationClass();
该方法的主要遍历当前的堆栈信息,获取main方法的class类,方法详情信息
/*** 获取主类class对象* @return*/private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();StackTraceElement[] var2 = stackTrace;int var3 = stackTrace.length;for(int var4 = 0; var4 < var3; ++var4) {StackTraceElement stackTraceElement = var2[var4];if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}} catch (ClassNotFoundException var6) {}return null;}
小结
创建SpringApplication对象,要设置一下属性信息
- 设置应用类型
- 设置初始化器
- 设置监听器
- 设置主类class对象