文章SpringBoot源码解析之SpringBoot自动装配原理中,我们分析了SpringBoot的自动装配原理以及@SpringBootApplication注解的原理,本篇文章则继续基于上篇文章中的main方法来分析SpringApplication这个类
@SpringBootApplicationpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}
点击run方法一路跟踪下来,发现首先做的是实例化SpringApplication对象实例
public static ConfigurableApplicationContext run(Class> primarySource, String... args) { return run(new Class>[] { primarySource }, args);}public static ConfigurableApplicationContext run(Class>[] primarySources,String[] args) {return new SpringApplication(primarySources).run(args);}//创建`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)); //1. 获取当前web环境this.webApplicationType = WebApplicationType.deduceFromClasspath(); //2. 加载所有的ApplicationContextInitializer和ApplicationListener的实现类setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //3. 找到入口方法main所在的类,赋值给全局变量mainApplicationClassthis.mainApplicationClass = deduceMainApplicationClass();}
- 首先看一下WebApplicationType.deduceFromClasspath()方法
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";private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";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;}
意思就是根据当前项目中是否存在上方的几个类来推断出当前的web环境,这里因为SpringBoot默认使用的web框架是SpringMVC,所以最后返回结果为WebApplicationType.SERVLET
- 加载所有的ApplicationContextInitializer和ApplicationListener的实现类
private Collection getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class>[] {});}private Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates Set names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances;}
可以看到主要还是用的SpringFactoriesLoader这个类去加载这两个接口的实现类,加载到类以后使用反射的方式构造出这些类的实例,然后根据这些实现类上的Order注解的值进行排序
- 找到入口方法main所在的类,赋值给全局变量mainApplicationClass
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;}