springboot 启动流程

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值