本文共 3907 字,大约阅读时间需要 13 分钟。
SpringBoot版本为 2.1.1.RELEASE
@SpringBootApplicationpublic class SpringbootDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootDemoApplication.class, args); }
这是一个SpringBoot项目的启动类,在主方法内,调用了SpringApplication类的静态run( )方法,并且把启动类的字节码和主方法的参数作为函数入参。
我们以Debug方式来运行代码,可以发现SpringBoot项目在启动时会先创建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); }public SpringApplication(Class ... primarySources) { this(null, primarySources); }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(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
可以发现,其实在创建SpringApplcation对象时就是把启动类的Class类作为入参调用了SpringApplication类的构造方法。
下面将会重点说明一下这个构造方法: 1. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); 这行代码是将启动类存储到SpringApplicationd对象的primarySources 属性中 2. this.webApplicationType = WebApplicationType.deduceFromClasspath(); 这个方法是推断Web应用类型static WebApplicationType deduceFromClasspath() { //存在DispatcherHander但是不存在DispatcherServlet时,推断为WebFlux类型 if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } // 当Servlet和ConfigurableWebApplicationContext均不存在时,推断为非Web应用 for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
由于我们只引入了web依赖,所以返回为Servlet
这个方法是用来加载Spring应用上下文初始化器的。
我们debug进入getSpringFactoriesInstances() 中:privateCollection 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类的loadFactoryNames()方法从类路径下的 “META-INF/spring.factories” 文件中找到所有的 “ApplicationContextInitializer”,然后保存到 SpringApplication的initializers属性中。
在下图中,我们可以看到通过getSpringFactoriesInstances()方法,initializers属性中保存了6个初始化器下一篇文章将会讲解SpringApplicaiton中run()方法的运行。
转载地址:http://xqmbi.baihongyu.com/