spring 启动
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//从springboot
return new SpringApplication(primarySources).run(args);
}
这里主要分为两步,一个是spring Application的构造方法
另一步时执行 run()
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));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
getSpringFactoriesInstances(…)这个放在在springboot 的自动配置里面能看到,就是从META-INF/spring.factories这个文件里面取出kv对,然后将将这些kv对实例化,供后续使用,这里也是一样,而其实构造方法中最重要的两步就是取出了ApplicationContextInitializer和
ApplicationListener对象
run()
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);//获得 SpringApplicationRunListener 数组,并启动监听。
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 初始化环境,加入jvm参数 处理Profiles ,将其加入环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);//忽略
Banner printedBanner = printBanner(environment);//打印 Spring Banner
context = createApplicationContext();//创建Application servlet 对应AnnotationConfigServletWebServerApplicationContext
//继承自ServletWebServerApplicationContext
// /进行获得 SpringBootExceptionReporter 类型的对象数组。SpringBootExceptionReporter ,记录启动过程中的异常信息。
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//方法,主要是调用所有初始化类的 #initialize(...) 方法//主要是给context属性赋值
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);//调用spring的refresh,并且会启动tomcat(onRefresh)
afterRefresh(context, applicationArguments);//执行 Spring 容器的初始化的后置逻辑。默认实现为空
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);//,通知 SpringApplicationRunListener 的数组,Spring 容器启动完成
//调用 ApplicationRunner 或者 CommandLineRunner 的运行方法,这里是springboot提供的扩展点,用户可以根据根据需要自己继承这两个接口
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
//SpringBootExceptionReporter 进行处理,并抛出 IllegalStateException 异常
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 发布事件ApplicationReadyEvent
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
prepareEnvironment()
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
// 根据应用的类型创建不同的environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 对environment进行配置
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;
}
这里主要是对Environment(环境)进行一些初始化,并且会在configureEnvironment这个方法里面获取启动参数,加入环境
prepareContext()
这个方法里面有一步比较重要,就是执行 applyInitializers(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);
}
}
这里可以看到一个熟悉的接口 ApplicationContextInitializer ,在构造方法里面提到过
在一个Springboot应用中,classpath上会包含很多jar包,
有些jar包需要在ConfigurableApplicationContext#refresh()调用之前对应用上下文做一些初始化动作,
因此它们会提供自己的ApplicationContextInitializer实现类,然后放在自己的META-INF/spring.factories属性文件中,
这样相应的ApplicationContextInitializer实现类就会被SpringApplication#initialize发现
refreshContext(context)
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {}
}
//spring
refresh(context);
}
这里的 refresh ,里面会调用spring 的refresh
但是现在的Application类型是 AnnotationConfigServletWebServerApplicationContext 继承自ServletWebServerApplicationContext
而AnnotationConfigServletWebServerApplicationContext 的创建就是在 createApplicationContext() 创建的,会根据 web应用的类型创建对应的类型创建对应的 Application
在spring 的onRefresh()
onRefresh()
protected void onRefresh() {
super.onRefresh();
try {
//创建服务器
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
AnnotationConfigServletWebServerApplicationContext 继承自ServletWebServerApplicationContext,所以这里调用的onRefresh()是ServletWebServerApplicationContext的onRefresh,在这个方法里面会创建WebServer,这也就是所谓的内置tomcat
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {//忽略
...
}
initPropertySources();
}
这里主要是走if的逻辑,从ServletWebServerFactory 中获取WebServer的实例
那么ServletWebServerFactory 是什么?
在这个接口下有一些实例,例如tomcat对应的实例TomcatServletWebServerFactory,就是用来生产tomcat的对象
TomcatServletWebServerFactory.getWebServer()
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();//创建tomcat
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());//!!
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);//开启tomcat
}
这里非常直观的可以看到直接new 了一个Tomcat对象
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
initialize();
}
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
Context context = findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
// Remove service connectors so that protocol binding doesn't
// happen when the service is started.
removeServiceConnectors();
}
});
// Start the server to trigger initialization listeners
this.tomcat.start();
。。。。
}
然后再这个initialize()里面启动tomcat