1.SpringApplication
我们先创建一个基本的SpringBoot项目,然后找到SpringApplication.run()方法,并且查看里面的调用。
我们会发现此时是再次调用了run(),点击run()方法
里面是new了一个SpringApplication,我们把new SpringApplication(SpringbootApplication.class).run(args);
拿来替换main()方法中的SpringApplication.run(SpringbootApplication.class, args);
,运行,可以发现两者的鲜果是一样的。
我们可以查看到run方法有返回值。对象类型是ConfigurableApplicationContext。这个类可以设置我们的Banner。也就是我们平常启动显示出来的这个图标
进入new SpringApplication(SpringbootApplication.class).run(args);
的run()方法,可以查看到
这么一段代码,为什么要把start(),stop()圈出来呢?其实我们先看看这个stopWatch是干什么的类吧。
System.nanoTime()返回最准确的可用系统计时器的当前值,以毫微秒为单位。这也就是我们为什么在控制台可以看到有启动时间的原因,那么看到了start()和stop()也就是代表着启动结束了。我们后面再来分析这一段代码。
我们再来看到new SpringApplication(SpringbootApplication.class).run(args);
这一段,看看他的执行方法,点进去他在执行run方法之前会去执行this()方法。那么我们看看this()方法。
我们先从这里开始看
this.webApplicationType = WebApplicationType.deduceFromClasspath();
点击方法进入
其中
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";
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
查看是否有org.springframework.web.reactive.DispatcherHandler
之后的ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)
同理。假若全部为true则使用响应式WEB启动,
如果不存在"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"
则不嵌入web服务器。
否则,嵌入servlet服务器。
其实他return的数据只是进行了枚举包装
这张图片的内容我们也解释一下。
NONE
:应用程序不应作为Web应用程序运行,也不应启动嵌入式Web服务器。
SERVLET
:应用程序应作为基于servlet的Web应用程序运行,并应启动嵌入式servlet Web服务器。
REACTIVE
:应用程序应作为响应式Web应用程序运行,并应启动嵌入式响应式Web服务器。
这个webApplicationType 我们也可以以自己设置,在yml中设置,如下:
-
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
默认从这两个jar包的路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
-
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
从类路径下找到META-INF/spring.factories配置的所有ApplicationListener。一般都是查询上面图片中的配置。他们两个都会扫描所有的jar包中的spring.factories -
this.mainApplicationClass = deduceMainApplicationClass();
获取Main函数主类
2.@EnableAutoConfiguration
查看源码
借用@Import注册了AutoConfigurationImportSelector
那么我们看看AutoConfigurationImportSelector.java
看到这个方法getAutoConfigurationEntry()
再看到getCandidateConfigurations()方法,点击进去可以看到
getSpringFactoriesLoaderFactoryClass()方法被调用,看到SpringFactoriesLoader我们应该会很快的想到spring.factories这个文件,又是去扫描jar包里面的这个文件。我们可以去看看
在这里面
里面一共100+,其中一部分是不会被注入的,因为没有被引用。
在前面的文章我们都知道SpringMVC最重要的就是DispatcherServlet,在里面一搜索果然有关于他的。
里面还有一个ServletWebServerFactoryAutoConfiguration,这个也就是ServletFaactory,我们拿出来,去看看他做了什么。
圈出来的位置应该很熟悉了,这就是我们之前手动启动tomcat的Embedded吧?这个是后要,我们先查看这个Bean==>tomcatServletWebServerFactoryCustomizer在上述图片里面应该也有,我们看看他的底层是什么。
应该很熟悉吧?我们在yml中会经常使用到server.xxx
好了,现在我们再去查看刚刚提到的ServletWebServerFactoryConfiguration.EmbeddedTomcat
我们直接点击进去看。
他使用了@Bean注册了tomcatServletWebServerFactory,我们去看看这个被注册的bean,找到getWebServer()方法
这里应该很熟悉了。这里我们在手动启动tomcat的时候和这个操作差不多。这里就是启动tomcat,我们在创建这一部分打个断点。(后续使用)
我们在回来查看DispatcherServletAutoConfiguration这个bean。点击进去
这里我们可以找到DispatcherServletConfiguration,可以看到使用了@Bean,直接注册了DispatcherServlet
我们在此方法中随意打个断点。现在我们来思考,是DispatcherServlet先创建还是先启动tomcat,我们直接Debug,我们会发现会先启动Tomcat然后在去创建DispatcherServlet