通过查看springboot主配置类的main方法中,调用的是springApplication中的静态的run方法
@SpringBootApplication public class SpringbootWebRestfulcrudApplication { public static void main(String[] args) { SpringApplication.run(SpringbootWebRestfulcrudApplication.class, args); }进入到run方法中发现,springboot启动分为俩步,一个是实例化SpringApplication,将主配置类存到class数组中作为构造方法参数传进去
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }一路点进来,我们发现最后调用的这个构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; //这里判断是否有主配置类,如果没有,则抛一个异常,这个异常如果被处理后可以继续向下执行,如果没被处理,程序不会向下执行 Assert.notNull(primarySources, "PrimarySources must not be null"); //将主配置类存到一个HashSet集合中,赋值 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //同样也是给属性赋值,这个是web程序的属性,在WebApplicationType中会有三个属性NONE,SERVLET,REACTIVE this.webApplicationType = WebApplicationType.deduceFromClasspath(); //给initializers属性赋值,在getSpringFactoriesInstances里面我们可以找到调用了loadSpringFactories方法,最后获取的jar包中META-INF包下的Apring.factories这个配置文件中的ApplicationContextInitializer对应的属性 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //给listeners赋值,一样的道理,获取的是ApplicationListener对应的属性 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }这个deduceFromClasspath()方法中最重要的功能 是加载class功能,而class加载是依赖jar包是否引起而判断的,所以如果引入了javax.servlet.Servlet的jar,则会启动Servlet模式,如果引入的jar是spring-boot-starter-webflux,而且没引入servlet相关的jar,则会启动Reactive模式。
//判断当前的应用服务属于什么类型 static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; } private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet"; private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";loadSpringFactories里面可以看到获取了FACTORIES_RESOURCE_LOCATION属性,这个FACTORIES_RESOURCE_LOCATION属性就是"META-INF/spring.factories"也就是说获取META-INF包下的spring.factories文件里面ApplicationContextInitializer属性对应的值以集合的形式返回赋值给initializers属性
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); 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(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }最后调用的deduceMainApplicationClass方法,作用是获取主配置类的main方法,将这个类信息返回
private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }准备环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }创建ioc容器,根据webApplicationType里面的属性来判断(SERVLET,REACTIVE),最后使用BeanUtils反射创建ioc容器
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }配置上下文环境
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { //给ioc容器中的environment赋值(配置环境) context.setEnvironment(environment); //ioc的后置组件 postProcessApplicationContext(context); //之前new SpringApplication的时候,已经从各个jar包的META-INF下的spring.favtories里面获取到的ApplicationContextInitializer,调用里面的initialize方法 applyInitializers(context); //listeners还要回调contextPrepared这个方法 listeners.contextPrepared(context); //在listeners准备执行完成之后,还要调用ApplicationContextInitializer里面的contextLoaded方法 if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); } protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }